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]
Other format: [Raw text]

Re: [rfa] annotate blocks with C++ namespace information


David Carlton writes:
 > Just for reference, here's a slightly updated version of my namespace
 > patch, following Daniel's suggestions.  The only real change is that
 > it adds a new command "maint cplus first_component" and a new file
 > gdb.c++/maint.exp to test it.


Ok, I got around to this finally.  It is basically ok, except for the
line between what is c++ and what is symbol table stuff. I think that
more stuff can be pushed into cp-support.c. See below...

 > 
 > David Carlton
 > carlton at math dot stanford dot edu
 > 
 > 2003-03-17  David Carlton  <carlton at math dot stanford dot edu>
 > 
 > 	* Makefile.in (block.o): Depend on gdb_obstack_h and
 > 	cp_support_h.
 > 	(buildsym.o): Depend on cp_support_h.
 > 	(cp-support.o): Depend on gdb_string_h, demangle_h, gdb_assert_h,
 > 	gdb_obstack_h, symtab_h, symfile_h, and gdbcmd_h.
 > 	* jv-lang.c (get_java_class_symtab): Set BLOCK_NAMESPACE.
 > 	* dwarf2read.c (process_die): Set processing_has_namespace_info,
 > 	processing_current_namespace.
 > 	(read_namespace): Update processing_current_namespace; check for
 > 	anonymous namespaces.
 > 	(dwarf2_name): New function.
 > 	(dwarf2_extension): Ditto.
 > 	* cp-support.h: Update copyright, contributors.
 > 	Add inclusion guards.
 > 	Add opaque declaration for struct obstack.
 > 	Add declarations for cp_find_first_component,
 > 	cp_entire_prefix_len, cp_add_using, cp_copy_usings,
 > 	cp_is_anonymous.
 > 	(struct using_direct): New struct.
 > 	* cp-support.c: Update copyright, contributors.
 > 	Include gdb_assert.h, gdb_obstack.h, symtab.h, symfile.h,
 > 	gdbcmd.h, ctype.h.
 > 	New variable maint_cplus_cmd_list.
 > 	(cp_find_first_component): New function.
 > 	(cp_entire_prefix_len, cp_add_using, cp_copy_usings)
 > 	(cp_is_anonymous, maint_cplus_command, first_component_command)
 > 	(_initialize_cp_support): Ditto.
 > 	* buildsym.h: New variables processing_has_namespace_info and
 > 	processing_current_namespace.
 > 	Declare add_using_directive.
 > 	* buildsym.c: Include cp-support.h.
 > 	New variable using_list.
 > 	(add_symbol_to_list): Check for anonymous namespaces.
 > 	(scan_for_anonymous_namespaces): New function.
 > 	(add_using_directive): Ditto.
 > 	(finish_block): Set block's scope.
 > 	(start_symtab): Initialize processing_has_namespace_info and
 > 	using_list.
 > 	(end_symtab): Put the using list in the block.
 > 	* block.h: Add opaque declarations for structs
 > 	block_namespace_info, using_direct, and obstack.
 > 	Add declarations for block_set_scope and block_set_using.
 > 	(struct block): Add 'language_specific' member.
 > 	(BLOCK_NAMESPACE): New macro.
 > 	* block.c: Include gdb_obstack.h and cp-support.h.
 > 	(struct block_namespace_info): New struct.
 > 	(block_set_scope): New function.
 > 	(block_set_using, block_initialize_namespace): Ditto.
 > 
 > 2003-03-17  David Carlton  <carlton at math dot stanford dot edu>
 > 
 > 	* gdb.c++/maint.exp: New file.
 > 
 > Index: Makefile.in
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/Makefile.in,v
 > retrieving revision 1.341
 > diff -u -p -r1.341 Makefile.in
 > --- Makefile.in	5 Mar 2003 18:07:15 -0000	1.341
 > +++ Makefile.in	17 Mar 2003 21:50:37 -0000
 > @@ -1535,7 +1535,8 @@ ax-gdb.o: ax-gdb.c $(defs_h) $(symtab_h)
 >  	$(regcache_h)
 >  ax-general.o: ax-general.c $(defs_h) $(ax_h) $(value_h) $(gdb_string_h)
 >  bcache.o: bcache.c $(defs_h) $(gdb_obstack_h) $(bcache_h) $(gdb_string_h)
 > -block.o: block.c $(defs_h) $(block_h) $(symtab_h) $(symfile_h)
 > +block.o: block.c $(defs_h) $(block_h) $(symtab_h) $(symfile_h) \
 > +	$(gdb_obstack_h) $(cp_support_h)
 >  blockframe.o: blockframe.c $(defs_h) $(symtab_h) $(bfd_h) $(symfile_h) \
 >  	$(objfiles_h) $(frame_h) $(gdbcore_h) $(value_h) $(target_h) \
 >  	$(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h) \
 > @@ -1551,7 +1552,7 @@ buildsym.o: buildsym.c $(defs_h) $(bfd_h
 >  	$(symfile_h) $(objfiles_h) $(gdbtypes_h) $(gdb_assert_h) \
 >  	$(complaints_h)	$(gdb_string_h) $(expression_h) $(language_h) \
 >  	$(bcache_h) $(filenames_h) $(macrotab_h) $(demangle_h) $(buildsym_h) \
 > -	$(stabsread_h) $(block_h)
 > +	$(stabsread_h) $(block_h) $(cp_support_h)
 >  builtin-regs.o: builtin-regs.c $(defs_h) $(builtin_regs_h) $(gdbtypes_h) \
 >  	$(gdb_string_h) $(gdb_assert_h)
 >  c-lang.o: c-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
 > @@ -1596,7 +1597,9 @@ corelow.o: corelow.c $(defs_h) $(gdb_str
 >  	$(gdbthread_h) $(regcache_h) $(symfile_h) $(readline_h)
 >  cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) \
 >  	$(gdbcmd_h) $(ui_out_h) $(gdb_string_h)
 > -cp-support.o: cp-support.c $(defs_h) $(cp_support_h)
 > +cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
 > +	$(demangle_h) $(gdb_assert_h) $(gdb_obstack_h) $(symtab_h) \
 > +	$(symfile_h) $(gdbcmd_h)
 >  cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
 >  	$(gdbtypes_h) $(expression_h) $(value_h) $(command_h) $(gdbcmd_h) \
 >  	$(demangle_h) $(annotate_h) $(gdb_string_h) $(c_lang_h) $(target_h) \
 > Index: jv-lang.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/jv-lang.c,v
 > retrieving revision 1.15
 > diff -u -p -r1.15 jv-lang.c
 > --- jv-lang.c	25 Feb 2003 21:36:18 -0000	1.15
 > +++ jv-lang.c	17 Mar 2003 21:52:04 -0000
 > @@ -118,6 +118,7 @@ get_java_class_symtab (void)
 >        BLOCK_END (bl) = 0;
 >        BLOCK_FUNCTION (bl) = NULL;
 >        BLOCK_SUPERBLOCK (bl) = NULL;
 > +      BLOCK_NAMESPACE (bl) = NULL;
 >        BLOCK_GCC_COMPILED (bl) = 0;
 >        BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
 >  
 > Index: dwarf2read.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/dwarf2read.c,v
 > retrieving revision 1.88
 > diff -u -p -r1.88 dwarf2read.c
 > --- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
 > +++ dwarf2read.c	17 Mar 2003 21:51:42 -0000
 > @@ -853,6 +853,10 @@ static void process_die (struct die_info
 >  
 >  static char *dwarf2_linkage_name (struct die_info *);
 >  
 > +static char *dwarf2_name (struct die_info *die);
 > +
 > +static struct die_info *dwarf2_extension (struct die_info *die);
 > +
 >  static char *dwarf_tag_name (unsigned int);
 >  
 >  static char *dwarf_attr_name (unsigned int);
 > @@ -1753,6 +1757,11 @@ process_die (struct die_info *die, struc
 >      case DW_TAG_common_inclusion:
 >        break;
 >      case DW_TAG_namespace:
 > +      if (!processing_has_namespace_info)
 > +	{
 > +	  processing_has_namespace_info = 1;
 > +	  processing_current_namespace = "";
 > +	}
 >        read_namespace (die, objfile, cu_header);
 >        break;
 >      case DW_TAG_imported_declaration:
 > @@ -1763,6 +1772,11 @@ process_die (struct die_info *die, struc
 >  	 shouldn't in the C++ case, but conceivably could in the
 >  	 Fortran case, so we'll have to replace this gdb_assert if
 >  	 Fortran compilers start generating that info.  */
 > +      if (!processing_has_namespace_info)
 > +	{
 > +	  processing_has_namespace_info = 1;
 > +	  processing_current_namespace = "";
 > +	}
 >        gdb_assert (!die->has_children);
 >        break;
 >      default:
 > @@ -3157,13 +3171,59 @@ read_common_block (struct die_info *die,
 >  
 >  /* Read a C++ namespace.  */
 >  
 > -/* FIXME: carlton/2002-10-16: For now, we don't actually do anything
 > -   useful with the namespace data: we just process its children.  */
 > -
 >  static void
 >  read_namespace (struct die_info *die, struct objfile *objfile,
 >  		const struct comp_unit_head *cu_header)
 >  {
 > +  const char *previous_namespace = processing_current_namespace;
 > +  const char *name = NULL;
 > +  int is_anonymous;
 > +  struct die_info *current_die;
 > +
 > +  /* Loop through the extensions until we find a name.  */
 > +
 > +  for (current_die = die;
 > +       current_die != NULL;
 > +       current_die = dwarf2_extension (die))
 > +    {
 > +      name = dwarf2_name (current_die);
 > +      if (name != NULL)
 > +	break;
 > +    }
 > +
 > +  /* Is it an anonymous namespace?  */
 > +
 > +  is_anonymous = (name == NULL);
 > +  if (is_anonymous)
 > +    name = "(anonymous namespace)";
 > +
 > +  /* Now build the name of the current namespace.  */
 > +
 > +  if (previous_namespace[0] == '\0')
 > +    {
 > +      processing_current_namespace = name;
 > +    }
 > +  else
 > +    {
 > +      /* We need temp_name around because processing_current_namespace
 > +	 is a const char *.  */
 > +      char *temp_name = alloca (strlen (previous_namespace)
 > +				+ 2 + strlen(name) + 1);
 > +      strcpy (temp_name, previous_namespace);
 > +      strcat (temp_name, "::");
 > +      strcat (temp_name, name);
 > +
 > +      processing_current_namespace = temp_name;
 > +    }
 > +
 > +  /* If it's an anonymous namespace that we're seeing for the first
 > +     time, add a using directive.  */
 > +
 > +  if (is_anonymous && dwarf_attr (die, DW_AT_extension) == NULL)
 > +    add_using_directive (processing_current_namespace,
 > +			 strlen (previous_namespace),
 > +			 strlen (processing_current_namespace));
 > +
 >    if (die->has_children)
 >      {
 >        struct die_info *child_die = die->next;
 > @@ -3174,6 +3234,8 @@ read_namespace (struct die_info *die, st
 >  	  child_die = sibling_die (child_die);
 >  	}
 >      }
 > +
 > +  processing_current_namespace = previous_namespace;
 >  }
 >  
 >  /* Extract all information from a DW_TAG_pointer_type DIE and add to
 > @@ -5638,6 +5700,43 @@ dwarf2_linkage_name (struct die_info *di
 >    if (attr && DW_STRING (attr))
 >      return DW_STRING (attr);
 >    return NULL;
 > +}
 > +
 > +/* Get name of a die, return NULL if not found.  */
 > +
 > +static char *
 > +dwarf2_name (struct die_info *die)
 > +{
 > +  struct attribute *attr;
 > +
 > +  attr = dwarf_attr (die, DW_AT_name);
 > +  if (attr && DW_STRING (attr))
 > +    return DW_STRING (attr);
 > +  return NULL;
 > +}
 > +
 > +/* Return the die that this die in an extension of, or NULL if there
 > +   is none.  */
 > +
 > +static struct die_info *
 > +dwarf2_extension (struct die_info *die)
 > +{
 > +  struct attribute *attr;
 > +  struct die_info *extension_die;
 > +  unsigned int ref;
 > +
 > +  attr = dwarf_attr (die, DW_AT_extension);
 > +  if (attr == NULL)
 > +    return NULL;
 > +
 > +  ref = dwarf2_get_ref_die_offset (attr);
 > +  extension_die = follow_die_ref (ref);
 > +  if (!extension_die)
 > +    {
 > +      error ("Dwarf Error: Cannot find referent at offset %d.", ref);
 > +    }
 > +
 > +  return extension_die;
 >  }
 >  
 >  /* Convert a DIE tag into its string name.  */


dwarf2read.c changes OK.

 > Index: cp-support.h
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/cp-support.h,v
 > retrieving revision 1.1
 > diff -u -p -r1.1 cp-support.h
 > --- cp-support.h	14 Sep 2002 02:09:39 -0000	1.1
 > +++ cp-support.h	17 Mar 2003 21:51:29 -0000
 > @@ -1,7 +1,8 @@
 >  /* Helper routines for C++ support in GDB.
 > -   Copyright 2002 Free Software Foundation, Inc.
 > +   Copyright 2002, 2003 Free Software Foundation, Inc.
 >  
 >     Contributed by MontaVista Software.
 > +   Namespace support contributed by David Carlton.
 >  
 >     This file is part of GDB.
 >  
 > @@ -20,6 +21,42 @@
 >     Foundation, Inc., 59 Temple Place - Suite 330,
 >     Boston, MA 02111-1307, USA.  */
 >  
 > +#ifndef CP_SUPPORT_H
 > +#define CP_SUPPORT_H
 > +
 > +/* Opaque declarations.  */
 > +
 > +struct obstack;
 > +
 > +/* This struct is designed to store data from using directives.  It
 > +   says that names from namespace INNER should be visible within
 > +   namespace OUTER.  OUTER should always be a strict initial substring
 > +   of INNER.  These form a linked list; NEXT is the next element of
 > +   the list.  */
 > +
 > +struct using_direct
 > +{
 > +  char *inner;
 > +  char *outer;
 > +  struct using_direct *next;
 > +};
 > +
 >  extern char *class_name_from_physname (const char *physname);
 >  
 >  extern char *method_name_from_physname (const char *physname);
 > +
 > +extern unsigned int cp_find_first_component (const char *name);
 > +
 > +extern unsigned int cp_entire_prefix_len (const char *name);
 > +
 > +extern struct using_direct *cp_add_using (const char *name,
 > +					  unsigned int inner_len,
 > +					  unsigned int outer_len,
 > +					  struct using_direct *next);
 > +
 > +extern struct using_direct *cp_copy_usings (struct using_direct *using,
 > +					    struct obstack *obstack);
 > +
 > +extern int cp_is_anonymous (const char *namespace);
 > +
 > +#endif /* CP_SUPPORT_H */

 > Index: cp-support.c

I am going to ignore this file, you and Daniel already settled it, right?



 > ===================================================================
 > RCS file: /cvs/src/src/gdb/cp-support.c,v
 > retrieving revision 1.1
 > diff -u -p -r1.1 cp-support.c
 > --- cp-support.c	14 Sep 2002 02:09:39 -0000	1.1
 > +++ cp-support.c	17 Mar 2003 21:51:22 -0000
 > @@ -1,7 +1,8 @@
 >  /* Helper routines for C++ support in GDB.
 > -   Copyright 2002 Free Software Foundation, Inc.
 > +   Copyright 2002, 2003 Free Software Foundation, Inc.
 >  
 >     Contributed by MontaVista Software.
 > +   Namespace support contributed by David Carlton.
 >  
 >     This file is part of GDB.
 >  
 > @@ -21,9 +22,59 @@
 >     Boston, MA 02111-1307, USA.  */
 >  
 >  #include "defs.h"
 > +#include <ctype.h>
 >  #include "cp-support.h"
 >  #include "gdb_string.h"
 >  #include "demangle.h"
 > +#include "gdb_assert.h"
 > +#include "gdb_obstack.h"
 > +#include "symtab.h"
 > +#include "symfile.h"
 > +#include "gdbcmd.h"
 > +
 > +/* The list of "maint cplus" commands.  */
 > +
 > +static struct cmd_list_element *maint_cplus_cmd_list = NULL;
 > +
 > +/* The actual commands.  */
 > +
 > +static  void maint_cplus_command (char *arg, int from_tty);
 > +static void first_component_command (char *arg, int from_tty);
 > +
 > +/* Here are some random pieces of trivia to keep in mind while trying
 > +   to take apart demangled names:
 > +
 > +   - Names can contain function arguments or templates, so the process
 > +     has to be, to some extent recursive: maybe keep track of your
 > +     depth based on encountering <> and ().
 > +
 > +   - Parentheses don't just have to happen at the end of a name: they
 > +     can occur even if the name in question isn't a function, because
 > +     a template argument might be a type that's a function.
 > +
 > +   - Conversely, even if you're trying to deal with a function, its
 > +     demangled name might not end with ')': it could be a const or
 > +     volatile class method, in which case it ends with "const" or
 > +     "volatile".
 > +
 > +   - Parentheses are also used in anonymous namespaces: a variable
 > +     'foo' in an anonymous namespace gets demangled as "(anonymous
 > +     namespace)::foo".
 > +
 > +   - And operator names can contain parentheses or angle brackets.
 > +     Fortunately, I _think_ that operator names can only occur in a
 > +     fairly restrictive set of locations (in particular, they have be
 > +     at depth 0, don't they?).  */
 > +
 > +/* NOTE: carlton/2003-02-21: Daniel Jacobowitz came up with an example
 > +   where operator names don't occur at depth 0.  Sigh.  (It involved a
 > +   template argument that was a pointer: I hadn't realized that was
 > +   possible.)  Handling such edge cases does not seem like a
 > +   high-priority problem to me.  */
 > +
 > +/* FIXME: carlton/2003-03-13: We have several functions here with
 > +   overlapping functionality; can we combine them?  Also, do they
 > +   handle all the above considerations correctly?  */
 >  
 >  /* Find the last component of the demangled C++ name NAME.  NAME
 >     must be a method name including arguments, in order to correctly
 > @@ -138,4 +189,229 @@ method_name_from_physname (const char *p
 >  
 >    xfree (demangled_name);
 >    return ret;
 > +}
 > +
 > +/* This returns the length of first component of NAME, which should be
 > +   the demangled name of a C++ variable/function/method/etc.
 > +   Specifically, it returns the index of the first colon forming the
 > +   boundary of the first component: so, given 'A::foo' or 'A::B::foo'
 > +   it returns the 1, and given 'foo', it returns 0.  */
 > +
 > +/* Well, that's what it should do when called externally, but to make
 > +   the recursion easier, it also stops if it reaches an unexpected ')'
 > +   or '>'.  */
 > +
 > +/* NOTE: carlton/2003-03-13: This function is currently only intended
 > +   for internal use: it's probably not entirely safe when called on
 > +   user-generated input, because some of the 'index += 2' lines might
 > +   go past the end of malformed input.  */
 > +
 > +/* Let's optimize away calls to strlen("operator").  */
 > +
 > +#define LENGTH_OF_OPERATOR 8
 > +
 > +unsigned int
 > +cp_find_first_component (const char *name)
 > +{
 > +  /* Names like 'operator<<' screw up the recursion, so let's
 > +     special-case them.  I _hope_ they can only occur at the start of
 > +     a component.  */
 > +
 > +  unsigned int index = 0;
 > +
 > +  if (strncmp (name, "operator", LENGTH_OF_OPERATOR) == 0)
 > +    {
 > +      index += LENGTH_OF_OPERATOR;
 > +      while (isspace(name[index]))
 > +	++index;
 > +      switch (name[index])
 > +	{
 > +	case '<':
 > +	  if (name[index + 1] == '<')
 > +	    index += 2;
 > +	  else
 > +	    index += 1;
 > +	  break;
 > +	case '>':
 > +	case '-':
 > +	  if (name[index + 1] == '>')
 > +	    index += 2;
 > +	  else
 > +	    index += 1;
 > +	  break;
 > +	case '(':
 > +	  index += 2;
 > +	  break;
 > +	default:
 > +	  index += 1;
 > +	  break;
 > +	}
 > +    }
 > +
 > +  for (;; ++index)
 > +    {
 > +      switch (name[index])
 > +	{
 > +	case '<':
 > +	  /* Template; eat it up.  The calls to cp_first_component
 > +	     should only return (I hope!) when they reach the '>'
 > +	     terminating the component or a '::' between two
 > +	     components.  (Hence the '+ 2'.)  */
 > +	  index += 1;
 > +	  for (index += cp_find_first_component (name + index);
 > +	       name[index] != '>';
 > +	       index += cp_find_first_component (name + index))
 > +	    {
 > +	      gdb_assert (name[index] == ':');
 > +	      index += 2;
 > +	    }
 > +	  break;
 > +	case '(':
 > +	  /* Similar comment as to '<'.  */
 > +	  index += 1;
 > +	  for (index += cp_find_first_component (name + index);
 > +	       name[index] != ')';
 > +	       index += cp_find_first_component (name + index))
 > +	    {
 > +	      gdb_assert (name[index] == ':');
 > +	      index += 2;
 > +	    }
 > +	  break;
 > +	case '>':
 > +	case ')':
 > +	case '\0':
 > +	case ':':
 > +	  return index;
 > +	default:
 > +	  break;
 > +	}
 > +    }
 > +}
 > +
 > +/* If NAME is the fully-qualified name of a C++
 > +   function/variable/method/etc., this returns the length of its
 > +   entire prefix: all of the namespaces and classes that make up its
 > +   name.  Given 'A::foo', it returns 1, given 'A::B::foo', it returns
 > +   4, given 'foo', it returns 0.  */
 > +
 > +unsigned int
 > +cp_entire_prefix_len (const char *name)
 > +{
 > +  unsigned int current_len = cp_find_first_component (name);
 > +  unsigned int previous_len = 0;
 > +
 > +  while (name[current_len] != '\0')
 > +    {
 > +      gdb_assert (name[current_len] == ':');
 > +      previous_len = current_len;
 > +      /* Skip the '::'.  */
 > +      current_len += 2;
 > +      current_len += cp_find_first_component (name + current_len);
 > +    }
 > +
 > +  return previous_len;
 > +}
 > +
 > +/* Create a new struct using direct whose inner namespace is the
 > +   initial substring of NAME of leng INNER_LEN and whose outer
 > +   namespace is the initial substring of NAME of length OUTER_LENGTH.
 > +   Set its next member in the linked list to NEXT; allocate all memory
 > +   using xmalloc.  It copies the strings, so NAME can be a temporary
 > +   string.  */
 > +
 > +struct using_direct *
 > +cp_add_using (const char *name,
 > +	      unsigned int inner_len,
 > +	      unsigned int outer_len,
 > +	      struct using_direct *next)
 > +{
 > +  struct using_direct *retval;
 > +
 > +  gdb_assert (outer_len < inner_len);
 > +
 > +  retval = xmalloc (sizeof (struct using_direct));
 > +  retval->inner = savestring (name, inner_len);
 > +  retval->outer = savestring (name, outer_len);
 > +  retval->next = next;
 > +
 > +  return retval;
 > +}
 > +
 > +/* Make a copy of the using directives in the list pointed to by
 > +   USING, using OBSTACK to allocate memory.  Free all memory pointed
 > +   to by USING via xfree.  */
 > +
 > +extern struct using_direct *
 > +cp_copy_usings (struct using_direct *using,
 > +		struct obstack *obstack)
 > +{
 > +  if (using == NULL)
 > +    {
 > +      return NULL;
 > +    } 
 > +  else
 > +    {
 > +      struct using_direct *retval
 > +	= obstack_alloc (obstack, sizeof (struct using_direct));
 > +      retval->inner = obsavestring (using->inner, strlen (using->inner),
 > +				    obstack);
 > +      retval->outer = obsavestring (using->outer, strlen (using->outer),
 > +				    obstack);
 > +      retval->next = cp_copy_usings (using->next, obstack);
 > +
 > +      xfree (using->inner);
 > +      xfree (using->outer);
 > +      xfree (using);
 > +
 > +      return retval;
 > +    }
 > +}
 > +
 > +/* Test whether or not NAMESPACE looks like it mentions an anonymous
 > +   namespace; return nonzero if so.  */
 > +
 > +int
 > +cp_is_anonymous (const char *namespace)
 > +{
 > +  return (strstr (namespace, "(anonymous namespace)")
 > +	  != NULL);
 > +}
 > +
 > +/* Don't allow just "maintenance cplus".  */
 > +
 > +static  void
 > +maint_cplus_command (char *arg, int from_tty)
 > +{
 > +  printf_unfiltered ("\"maintenance cplus\" must be followed by the name of a command.\n");
 > +  help_list (maint_cplus_cmd_list, "maintenance cplus ", -1, gdb_stdout);
 > +}
 > +
 > +/* This is a front end for cp_find_first_component, for unit testing.
 > +   Be careful when using it: see the NOTE above
 > +   cp_find_first_component.  */
 > +
 > +static void
 > +first_component_command (char *arg, int from_tty)
 > +{
 > +  int len = cp_find_first_component (arg);
 > +  char *prefix = alloca (len + 1);
 > +
 > +  memcpy (prefix, arg, len);
 > +  prefix[len] = '\0';
 > +
 > +  printf_unfiltered ("%s\n", prefix);
 > +}
 > +
 > +void
 > +_initialize_cp_support (void)
 > +{
 > +  add_prefix_cmd ("cplus", class_maintenance, maint_cplus_command,
 > +		  "C++ maintenance commands.", &maint_cplus_cmd_list,
 > +		  "maintenance cplus ", 0, &maintenancelist);
 > +  add_alias_cmd ("cp", "cplus", class_maintenance, 1, &maintenancelist);
 > +
 > +  add_cmd ("first_component", class_maintenance, first_component_command,
 > +	   "Print the first class/namespace component of NAME.",
 > +	   &maint_cplus_cmd_list);
 > +		  
 >  }
 > Index: buildsym.h
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/buildsym.h,v
 > retrieving revision 1.11
 > diff -u -p -r1.11 buildsym.h
 > --- buildsym.h	20 Feb 2003 00:01:05 -0000	1.11
 > +++ buildsym.h	17 Mar 2003 21:51:06 -0000
 > @@ -85,6 +85,18 @@ EXTERN unsigned char processing_gcc_comp
 >  
 >  EXTERN unsigned char processing_acc_compilation;
 >  
 > +/* When set, the file that we're processing seems to have debugging
 > +   info for C++ namespaces, so buildsym.c shouldn't try to guess
 > +   namespace info itself.  */
 > +
 > +EXTERN unsigned char processing_has_namespace_info;
 > +
 > +/* If processing_has_namespace_info is nonzero, this string should
 > +   contain the name of the current namespace.  The string is
 > +   temporary; copy it if you need it.  */
 > +
 > +EXTERN const char *processing_current_namespace;
 > +
 >  /* Count symbols as they are processed, for error messages.  */
 >  
 >  EXTERN unsigned int symnum;
 > @@ -228,6 +240,9 @@ extern void add_symbol_to_list (struct s
 >  
 >  extern struct symbol *find_symbol_in_list (struct pending *list,
 >  					   char *name, int length);
 > +
 > +extern void add_using_directive (const char *name, unsigned int outer_length,
 > +				 unsigned int inner_length);
 >  
 >  extern void finish_block (struct symbol *symbol,
 >  			  struct pending **listhead,
 > Index: buildsym.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/buildsym.c,v
 > retrieving revision 1.31
 > diff -u -p -r1.31 buildsym.c
 > --- buildsym.c	25 Feb 2003 21:36:17 -0000	1.31
 > +++ buildsym.c	17 Mar 2003 21:51:00 -0000
 > @@ -44,6 +44,8 @@
 >  #include "macrotab.h"
 >  #include "demangle.h"		/* Needed by SYMBOL_INIT_DEMANGLED_NAME.  */
 >  #include "block.h"
 > +#include "cp-support.h"
 > +
 >  /* Ask buildsym.h to define the vars it normally declares `extern'.  */
 >  #define	EXTERN
 >  /**/
 > @@ -63,8 +65,15 @@ static struct pending *free_pendings;
 >     otherwise empty symtab from being tossed.  */
 >  
 >  static int have_line_numbers;
 > +
 > +/* List of using directives that are active in the current file.  */
 > +
 > +static struct using_direct *using_list;
 > +

see below for some thoughts.....

 >  
 >  static int compare_line_numbers (const void *ln1p, const void *ln2p);
 > +
 > +static void scan_for_anonymous_namespaces (struct symbol *symbol);
 >  
 >  
 >  /* Initial sizes of data structures.  These are realloc'd larger if
 > @@ -91,7 +100,10 @@ add_free_pendings (struct pending *list)
 >      }
 >  }
 >        
 > -/* Add a symbol to one of the lists of symbols.  */
 > +/* Add a symbol to one of the lists of symbols.  While we're at it, if
 > +   we're in the C++ case and don't have full namespace debugging info,
 > +   check to see if it references an anonymous namespace; if so, add an
 > +   appropriate using directive.  */
 >  
 >  void
 >  add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
 > @@ -122,6 +134,61 @@ add_symbol_to_list (struct symbol *symbo
 >      }
 >  
 >    (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
 > +
 > +  /* Check to see if we might need to look for a mention of anonymous
 > +     namespaces.  */
 > +  
 > +   if (SYMBOL_LANGUAGE (symbol) == language_cplus
 > +       && !processing_has_namespace_info
 > +       && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
 > +     scan_for_anonymous_namespaces (symbol);
 > +}

OK.

 > +
 > +/* Check to see if a symbol is contained within an anonymous
 > +   namespace; if so, add an appropriate using directive.  */
 > +
 > +/* Optimize away strlen ("(anonymous namespace)").  */
 > +
 > +#define ANONYMOUS_NAMESPACE_LEN 21
 > +
 > +static void
 > +scan_for_anonymous_namespaces (struct symbol *symbol)
 > +{
 > +  const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
 > +  unsigned int previous_component;
 > +  unsigned int next_component;
 > +  const char *len;
 > +
 > +  /* Start with a quick-and-dirty check for mention of "(anonymous
 > +     namespace)".  */
 > +
 > +  if (!cp_is_anonymous (name))
 > +    return;
 > +
 > +  previous_component = 0;
 > +  next_component = cp_find_first_component (name + previous_component);
 > +
 > +  while (name[next_component] == ':')
 > +    {
 > +      if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN
 > +	  && strncmp (name + previous_component,
 > +		      "(anonymous namespace)",
 > +		      ANONYMOUS_NAMESPACE_LEN) == 0)
 > +	{
 > +	  /* We've found a component of the name that's an anonymous
 > +	     namespace.  So add symbols in it to the namespace given
 > +	     by the previous component if there is one, or to the
 > +	     global namespace if there isn't.  */
 > +	  add_using_directive (name,
 > +			       previous_component == 0
 > +			       ? 0 : previous_component - 2,
 > +			       next_component);
 > +	}
 > +      /* The "+ 2" is for the "::".  */
 > +      previous_component = next_component + 2;
 > +      next_component = (previous_component
 > +			+ cp_find_first_component (name + previous_component));
 > +    }
 >  }
 >  

Should this function be in cp-support.c? You could tighten the
interface a bit, by passing in the name of the symbol only, instead of
the symbol. This way it would definitely belong in cp-support.c (...dirty
plan to delegate c++ stuff to Daniel in an inequivocable manner..).


 >  /* Find a symbol named NAME on a LIST.  NAME need not be
 > @@ -149,6 +216,34 @@ find_symbol_in_list (struct pending *lis
 >    return (NULL);
 >  }
 >  
 > +/* Add a using directive to using_list.  NAME is the start of a string
 > +   that should contain the namespaces we want to add as initial
 > +   substrings, OUTER_LENGTH is the end of the outer namespace, and
 > +   INNER_LENGTH is the end of the inner namespace.  If the using
 > +   directive in question has already been added, don't add it
 > +   twice.  */
 > +
 > +void
 > +add_using_directive (const char *name, unsigned int outer_length,
 > +		     unsigned int inner_length)
 > +{
 > +  struct using_direct *current;
 > +  struct using_direct *new;
 > +
 > +  /* Has it already been added?  */
 > +
 > +  for (current = using_list; current != NULL; current = current->next)
 > +    {
 > +      if ((strncmp (current->inner, name, inner_length) == 0)
 > +	  && (strlen (current->inner) == inner_length)
 > +	  && (strlen (current->outer) == outer_length))
 > +	return;
 > +    }
 > +
 > +  using_list = cp_add_using (name, inner_length, outer_length,
 > +			     using_list);
 > +}
 > +

This too, could be in cp-support.c, it has no knowledge of symbols,
etc.  Hmm, but it touches using_list. Which opens the question of
whether using_list should be in cp-support.c as well, so that the
interface is just using-list, exported in cp-support.h. It would
certainly make things cleaner. Not to mention that then you can check
stuff in w/o waiting for me. The struct using_direct could also be
made opaque, I think.

 >  /* At end of reading syms, or in case of quit, really free as many
 >     `struct pending's as we can easily find. */
 >  
 > @@ -280,6 +375,7 @@ finish_block (struct symbol *symbol, str
 >    BLOCK_END (block) = end;
 >    /* Superblock filled in when containing block is made */
 >    BLOCK_SUPERBLOCK (block) = NULL;
 > +  BLOCK_NAMESPACE (block) = NULL;
 >  
 >    BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
 >  
 > @@ -372,6 +468,41 @@ finish_block (struct symbol *symbol, str
 >  		}
 >  	    }
 >  	}
 > +
 > +      /* If we're in the C++ case, record the namespace that the
 > +	 function was defined in.  Make sure that the name was
 > +	 originally mangled: if not, there certainly isn't any
 > +	 namespace information to worry about!  */
 > +      if (SYMBOL_LANGUAGE (symbol) == language_cplus
 > +	  && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
 > +	{
 > +	  if (processing_has_namespace_info)
 > +	    {
 > +	      block_set_scope
 > +		(block, obsavestring (processing_current_namespace,
 > +				      strlen (processing_current_namespace),
 > +				      &objfile->symbol_obstack),
 > +		 &objfile->symbol_obstack);
 > +	    }
 > +	  else
 > +	    {
 > +	      /* Try to figure out the appropriate namespace from the
 > +		 demangled name.  */
 > +
 > +	      /* FIXME: carlton/2003-02-21: If the function in
 > +		 question is a method of a class, the name will
 > +		 actually include the name of the class as well.  This
 > +		 should be harmless, but is a little unfortunate.  */
 > +
 > +	      const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
 > +	      unsigned int prefix_len = cp_entire_prefix_len (name);
 > +
 > +	      block_set_scope (block,
 > +			       obsavestring (name, prefix_len,
 > +					     &objfile->symbol_obstack),
 > +			       &objfile->symbol_obstack);
 > +	    }
 > +	}
 >      }
 >    else
 >      {
 > @@ -803,6 +934,8 @@ start_symtab (char *name, char *dirname,
 >    global_symbols = NULL;
 >    within_function = 0;
 >    have_line_numbers = 0;
 > +  processing_has_namespace_info = 0;
 > +  using_list = NULL;
 >  

processing_has_namespace_info: there is one per symtab, yes?
I mean, it is set to 0 only here, just want to make sure.

 >    /* Context stack is initially empty.  Allocate first one with room
 >       for 10 levels; reuse it forever afterward.  */
 > @@ -935,6 +1068,14 @@ end_symtab (CORE_ADDR end_addr, struct o
 >        finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
 >  		    objfile);
 >        blockvector = make_blockvector (objfile);
 > +      if (using_list != NULL)
 > +	{
 > +	  block_set_using (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
 > +			   cp_copy_usings (using_list,

Should this function be called something like cp_dup_usings? But you
are freeing the original copy, right? Why do you need to copy it over?

 > +					   &objfile->symbol_obstack),
 > +			   &objfile->symbol_obstack);
 > +	  using_list = NULL;

If you move using_list in cp-support.c you could even introduce a
method that sets it to NULL, and another to check if it is
null. Nothing else would be needed, all other manipulations would be
done in cp-support.c.

 > +	}
 >      }
 >  
 >  #ifndef PROCESS_LINENUMBER_HOOK
 > Index: block.h
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/block.h,v
 > retrieving revision 1.2
 > diff -u -p -r1.2 block.h
 > --- block.h	20 Feb 2003 00:01:05 -0000	1.2
 > +++ block.h	17 Mar 2003 21:50:53 -0000
 > @@ -26,6 +26,9 @@
 >  
 >  struct symbol;
 >  struct symtab;
 > +struct block_namespace_info;
 > +struct using_direct;
 > +struct obstack;
 >  
 >  /* All of the name-scope contours of the program
 >     are represented by `struct block' objects.
 > @@ -74,6 +77,22 @@ struct block
 >  
 >    struct block *superblock;
 >  
 > +  /* Used for language-specific info.  */
 > +
 > +  union
 > +  {
 > +    struct
 > +    {
 > +      /* Contains information about namespace-related info relevant to
 > +	 this block: using directives and the current namespace
 > +	 scope.  */
 > +      
 > +      struct block_namespace_info *namespace;
 > +    }
 > +    cplus_specific;
 > +  }
 > +  language_specific;
 > +
 >    /* Version of GCC used to compile the function corresponding
 >       to this block, or 0 if not compiled with GCC.  When possible,
 >       GCC should be compatible with the native compiler, or if that
 > @@ -120,6 +139,7 @@ struct block
 >  #define BLOCK_FUNCTION(bl)	(bl)->function
 >  #define BLOCK_SUPERBLOCK(bl)	(bl)->superblock
 >  #define BLOCK_GCC_COMPILED(bl)	(bl)->gcc_compile_flag
 > +#define BLOCK_NAMESPACE(bl)   (bl)->language_specific.cplus_specific.namespace
 >  #define BLOCK_HASHTABLE(bl)	(bl)->hashtable
 >  
 >  /* For blocks without a hashtable (BLOCK_HASHTABLE (bl) == 0) only.  */
 > @@ -179,5 +199,12 @@ extern struct blockvector *blockvector_f
 >  extern struct block *block_for_pc (CORE_ADDR);
 >  
 >  extern struct block *block_for_pc_sect (CORE_ADDR, asection *);
 > +
 > +extern void block_set_scope (struct block *block, const char *scope,
 > +			     struct obstack *obstack);
 > +
 > +extern void block_set_using (struct block *block,
 > +			     struct using_direct *using,
 > +			     struct obstack *obstack);
 >  
 >  #endif /* BLOCK_H */
 > Index: block.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/block.c,v
 > retrieving revision 1.2
 > diff -u -p -r1.2 block.c
 > --- block.c	20 Feb 2003 00:01:05 -0000	1.2
 > +++ block.c	17 Mar 2003 21:50:44 -0000
 > @@ -23,6 +23,21 @@
 >  #include "block.h"
 >  #include "symtab.h"
 >  #include "symfile.h"
 > +#include "gdb_obstack.h"
 > +#include "cp-support.h"
 > +
 > +/* This is used by struct block to store namespace-related info for
 > +   C++ files, namely using declarations and the current namespace in
 > +   scope.  */
 > +
 > +struct block_namespace_info
 > +{
 > +  const char *scope;
 > +  struct using_direct *using;
 > +};
 > +
 > +static void block_initialize_namespace (struct block *block,
 > +					struct obstack *obstack);
 >  
 >  /* Return Nonzero if block a is lexically nested within block b,
 >     or if a and b have the same pc range.
 > @@ -138,4 +153,49 @@ struct block *
 >  block_for_pc (register CORE_ADDR pc)
 >  {
 >    return block_for_pc_sect (pc, find_pc_mapped_section (pc));
 > +}
 > +
 > +/* Now come some functions designed to deal with C++ namespace
 > +   issues.  */
 > +
 > +/* Set BLOCK's scope member to SCOPE; if needed, allocate memory via
 > +   OBSTACK.  (It won't make a copy of SCOPE, however, so that already
 > +   has to be allocated correctly.)  */
 > +
 > +void
 > +block_set_scope (struct block *block, const char *scope,
 > +		 struct obstack *obstack)
 > +{
 > +  block_initialize_namespace (block, obstack);
 > +
 > +  BLOCK_NAMESPACE (block)->scope = scope;
 > +}
 > +
 > +/* Set BLOCK's using member to USING; if needed, allocate memory via
 > +   OBSTACK.  (It won't make a copy of USING, however, so that already
 > +   has to be allocated correctly.)  */
 > +
 > +void
 > +block_set_using (struct block *block,
 > +		 struct using_direct *using,
 > +		 struct obstack *obstack)
 > +{
 > +  block_initialize_namespace (block, obstack);
 > +
 > +  BLOCK_NAMESPACE (block)->using = using;
 > +}
 > +
 > +/* If BLOCK_NAMESPACE (block) is NULL, allocate it via OBSTACK and
 > +   ititialize its members to zero.  */
 > +
 > +static void
 > +block_initialize_namespace (struct block *block, struct obstack *obstack)
 > +{
 > +  if (BLOCK_NAMESPACE (block) == NULL)
 > +    {
 > +      BLOCK_NAMESPACE (block)
 > +	= obstack_alloc (obstack, sizeof (struct block_namespace_info));
 > +      BLOCK_NAMESPACE (block)->scope = NULL;
 > +      BLOCK_NAMESPACE (block)->using = NULL;
 > +    }
 >  }

block.c changes OK.


The below is not my to approve.

 > --- /dev/null	Thu Apr 11 07:25:15 2002
 > +++ maint.exp	Mon Mar 17 13:33:14 2003
 > @@ -0,0 +1,79 @@
 > +# Copyright 2003 Free Software Foundation Inc.
 > +
 > +# 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.  
 > +
 > +# Please email any bugs, comments, and/or additions to this file to:
 > +# bug-gdb at prep dot ai dot mit dot edu
 > +
 > +
 > +# This file tests C++-specific maintenance commands and help on those.
 > +
 > +# Currently, no source file is used.
 > +
 > +if $tracelevel then {
 > +        strace $tracelevel
 > +        }
 > +
 > +# Test the help messages.
 > +
 > +proc test_help {} {
 > +    gdb_test "help maintenance cplus" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
 > +
 > +    gdb_test "help maint cp" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
 > +
 > +    gdb_test "maint cp" "\"maintenance cplus\" must be followed by the name of a command.\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
 > +
 > +    gdb_test "help maint cp first_component" "Print the first class/namespace component of NAME."
 > +}
 > +
 > +# This is used when NAME should contain only a single component.  Be
 > +# careful to make sure that parentheses get escaped properly.
 > +proc test_single_component {name} {
 > +    set matchname [string_to_regexp "$name"]
 > +    gdb_test "maint cp first_component $name" "$matchname"
 > +}
 > +
 > +proc test_first_component {} {
 > +    test_single_component "foo"
 > +    test_single_component "operator<<"
 > +    test_single_component "operator>>"
 > +    test_single_component "operator ->"
 > +    test_single_component "operator()"
 > +    test_single_component "operator>"
 > +    test_single_component "operator<"
 > +    test_single_component "operator ->"
 > +    test_single_component "operator  ->"
 > +
 > +    test_single_component "foo()"
 > +    test_single_component "foo(int)"
 > +    test_single_component "foo(X::Y)"
 > +    test_single_component "foo(X::Y, A::B)"
 > +    test_single_component "foo(std::basic_streambuf<wchar_t,std::char_traits<wchar_t> >)"
 > +    test_single_component "operator>(X::Y)"
 > +
 > +    gdb_test "maint cp first_component foo::bar" "foo"
 > +    gdb_test "maint cp first_component foo::bar::baz" "foo"
 > +    gdb_test "maint cp first_component C<A>::bar" "C<A>"
 > +    gdb_test "maint cp first_component C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >::bar" "C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >"
 > +}
 > +
 > +gdb_exit
 > +gdb_start
 > +
 > +test_help
 > +test_first_component
 > +
 > +gdb_exit
 > +return 0


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