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


On Mon, 14 Apr 2003 22:30:11 -0400, Elena Zannoni <ezannoni at redhat dot com> said:

> I see it more as building language specific structures, and letting
> symtabs have a pointer to those. I think the cp-namespace.c idea is a
> good compromise.

Excellent!  Here's what I've committed: it's the same as before,
except that a lot of what was added to buildsym.c is in
cp-namespace.c, as is a lot of what was added to cp-support.c.  No
substantial changes otherwise.

If I could get a final decision on the fate of
lookup_symbol_aux_minsyms, I'd appreciate it, because that will affect
the details of the next patch in this series.  Which will probably
take me a little while to prepare, anyways: I'm fairly busy for the
rest of this week, so it might have to wait until next week.

David Carlton
carlton at math dot stanford dot edu

2003-04-15  David Carlton  <carlton at math dot stanford dot edu>

	* Makefile.in (SFILES): Add cp-namespace.c.
	(COMMON_OBS): Add cp-namespace.o.
	(block.o): Depend on gdb_obstack_h and cp_support_h.
	(buildsym.o): Depend on cp_support_h.
	(cp-namespace.o): New.
	(cp-support.o): Depend on gdb_string_h, demangle_h, gdb_assert_h,
	gdb_obstack_h, symtab_h, symfile_h, and gdbcmd_h.
	(dwarf2read.o): Depend on cp_support_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 structs obstack, block, symbol.
	(struct using_direct): New struct.
	Add declarations for cp_find_first_component,
	cp_entire_prefix_len, processing_has_namespace_info,
	processing_current_namespace, cp_is_anonymous,
	cp_add_using_directive, cp_initialize_namespace,
	cp_finalize_namespace, cp_set_block_scope,
	cp_scan_for_anonymous_namespaces.
	* cp-namespace.c: New file.
	* cp-support.c: Update copyright.
	Include ctype.h, gdb_assert.h, gdbcmd.h.
	New variable maint_cplus_cmd_list.
	(cp_find_first_component): New function.
	(cp_entire_prefix_len, maint_cplus_command)
	(first_component_command, _initialize_cp_support): Ditto.
	* buildsym.c: Include cp-support.h.
	New variable using_list.
	(add_symbol_to_list): Check for anonymous namespaces.
	(finish_block): Set block's scope.
	(start_symtab): Initialize C++ namespace support.
	(end_symtab): Finalize C++ namespace support.
	* 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.363
diff -u -p -r1.363 Makefile.in
--- Makefile.in	14 Apr 2003 18:42:26 -0000	1.363
+++ Makefile.in	15 Apr 2003 22:28:30 -0000
@@ -512,7 +512,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	c-exp.y c-lang.c c-typeprint.c c-valprint.c \
 	charset.c cli-out.c coffread.c coff-pe-read.c \
 	complaints.c completer.c corefile.c \
-	cp-abi.c cp-support.c cp-valprint.c \
+	cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
 	dbxread.c demangle.c disasm.c doublest.c \
 	dummy-frame.c dwarfread.c dwarf2expr.c dwarf2loc.c dwarf2read.c \
 	elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
@@ -864,6 +864,7 @@ COMMON_OBS = version.o blockframe.o brea
 	frame.o frame-unwind.o doublest.o \
 	frame-base.o \
 	gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o \
+	cp-namespace.o \
 	reggroups.o
 
 OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
@@ -1551,7 +1552,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) \
@@ -1567,7 +1569,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) \
@@ -1613,7 +1615,10 @@ 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-namespace.o: cp-namespace.c $(defs_h) $(cp_support_h) $(gdb_obstack_h) \
+	$(symtab_h) $(symfile_h) $(gdb_assert_h) $(block_h)
+cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
+	$(demangle_h) $(gdb_assert_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) \
@@ -1666,7 +1671,7 @@ dwarf2read.o: dwarf2read.c $(defs_h) $(b
 	$(symfile_h) $(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) \
 	$(demangle_h) $(expression_h) $(filenames_h) $(macrotab_h) \
 	$(language_h) $(complaints_h) $(bcache_h) $(dwarf2expr_h) \
-	$(dwarf2loc_h) $(gdb_string_h) $(gdb_assert_h)
+	$(dwarf2loc_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h)
 dwarfread.o: dwarfread.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(symfile_h) \
 	$(objfiles_h) $(elf_dwarf_h) $(buildsym_h) $(demangle_h) \
 	$(expression_h) $(language_h) $(complaints_h) $(gdb_string_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;
+    }
 }
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: 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	15 Apr 2003 22:42:21 -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
 /**/
@@ -91,7 +93,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 +127,12 @@ 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)
+    cp_scan_for_anonymous_namespaces (symbol);
 }
 
 /* Find a symbol named NAME on a LIST.  NAME need not be
@@ -280,6 +291,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 +384,12 @@ finish_block (struct symbol *symbol, str
 		}
 	    }
 	}
+
+      /* If we're in the C++ case, set the block's scope.  */
+      if (SYMBOL_LANGUAGE (symbol) == language_cplus)
+	{
+	  cp_set_block_scope (symbol, block, &objfile->symbol_obstack);
+	}
     }
   else
     {
@@ -814,6 +832,10 @@ start_symtab (char *name, char *dirname,
     }
   context_stack_depth = 0;
 
+  /* Set up support for C++ namespace support, in case we need it.  */
+
+  cp_initialize_namespace ();
+
   /* Initialize the list of sub source files with one entry for this
      file (the top-level source file).  */
 
@@ -935,6 +957,8 @@ 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);
+      cp_finalize_namespace (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
+			     &objfile->symbol_obstack);
     }
 
 #ifndef PROCESS_LINENUMBER_HOOK
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ cp-namespace.c	Tue Apr 15 15:39:59 2003
@@ -0,0 +1,266 @@
+/* Helper routines for C++ support in GDB.
+   Copyright 2003 Free Software Foundation, Inc.
+
+   Contributed by David Carlton.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "cp-support.h"
+#include "gdb_obstack.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "gdb_assert.h"
+#include "block.h"
+
+/* When set, the file that we're processing seems to have debugging
+   info for C++ namespaces, so cp-namespace.c shouldn't try to guess
+   namespace info itself.  */
+
+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.  */
+
+const char *processing_current_namespace;
+
+/* List of using directives that are active in the current file.  */
+
+static struct using_direct *using_list;
+
+static struct using_direct *cp_add_using (const char *name,
+					  unsigned int inner_len,
+					  unsigned int outer_len,
+					  struct using_direct *next);
+
+static struct using_direct *cp_copy_usings (struct using_direct *using,
+					    struct obstack *obstack);
+
+/* Set up support for dealing with C++ namespace info in the current
+   symtab.  */
+
+void cp_initialize_namespace ()
+{
+  processing_has_namespace_info = 0;
+  using_list = NULL;
+}
+
+/* Add all the using directives we've gathered to the current symtab.
+   STATIC_BLOCK should be the symtab's static block; OBSTACK is used
+   for allocation.  */
+
+void
+cp_finalize_namespace (struct block *static_block,
+		       struct obstack *obstack)
+{
+  if (using_list != NULL)
+    {
+      block_set_using (static_block,
+		       cp_copy_usings (using_list, obstack),
+		       obstack);
+      using_list = NULL;
+    }
+}
+
+/* Check to see if SYMBOL refers to an object contained within an
+   anonymous namespace; if so, add an appropriate using directive.  */
+
+/* Optimize away strlen ("(anonymous namespace)").  */
+
+#define ANONYMOUS_NAMESPACE_LEN 21
+
+void
+cp_scan_for_anonymous_namespaces (const struct symbol *symbol)
+{
+  if (!processing_has_namespace_info
+      && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+    {
+      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.  */
+	      cp_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));
+	}
+    }
+}
+
+/* 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
+cp_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);
+}
+
+/* Record the namespace that the function defined by SYMBOL was
+   defined in, if necessary.  BLOCK is the associated block; use
+   OBSTACK for allocation.  */
+
+void
+cp_set_block_scope (const struct symbol *symbol,
+		    struct block *block,
+		    struct obstack *obstack)
+{
+  /* Make sure that the name was originally mangled: if not, there
+     certainly isn't any namespace information to worry about!  */
+
+  if (SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+    {
+      if (processing_has_namespace_info)
+	{
+	  block_set_scope
+	    (block, obsavestring (processing_current_namespace,
+				  strlen (processing_current_namespace),
+				  obstack),
+	     obstack);
+	}
+      else
+	{
+	  /* Try to figure out the appropriate namespace from the
+	     demangled name.  */
+
+	  /* FIXME: carlton/2003-04-15: 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, obstack),
+			   obstack);
+	}
+    }
+}
+
+/* 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);
+}
+
+/* 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.  */
+
+static 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.  */
+
+static 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;
+    }
+}
Index: cp-support.c
===================================================================
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	15 Apr 2003 23:05:07 -0000
@@ -1,5 +1,5 @@
 /* Helper routines for C++ support in GDB.
-   Copyright 2002 Free Software Foundation, Inc.
+   Copyright 2002, 2003 Free Software Foundation, Inc.
 
    Contributed by MontaVista Software.
 
@@ -21,9 +21,56 @@
    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 "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 +185,164 @@ 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;
+}
+
+/* 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: 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	15 Apr 2003 22:42:02 -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,61 @@
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#ifndef CP_SUPPORT_H
+#define CP_SUPPORT_H
+
+/* Opaque declarations.  */
+
+struct obstack;
+struct block;
+struct symbol;
+
+/* 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;
+};
+
+
+/* Functions from cp-support.c.  */
+
 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);
+
+
+/* Functions/variables from cp-namespace.c.  */
+
+extern unsigned char processing_has_namespace_info;
+
+extern const char *processing_current_namespace;
+
+extern int cp_is_anonymous (const char *namespace);
+
+extern void cp_add_using_directive (const char *name,
+				    unsigned int outer_length,
+				    unsigned int inner_length);
+
+extern void cp_initialize_namespace ();
+
+extern void cp_finalize_namespace (struct block *static_block,
+				   struct obstack *obstack);
+
+extern void cp_set_block_scope (const struct symbol *symbol,
+				struct block *block,
+				struct obstack *obstack);
+
+extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol);
+
+#endif /* CP_SUPPORT_H */
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.89
diff -u -p -r1.89 dwarf2read.c
--- dwarf2read.c	13 Apr 2003 15:43:35 -0000	1.89
+++ dwarf2read.c	15 Apr 2003 22:42:42 -0000
@@ -43,6 +43,7 @@
 #include "bcache.h"
 #include "dwarf2expr.h"
 #include "dwarf2loc.h"
+#include "cp-support.h"
 
 #include <fcntl.h>
 #include "gdb_string.h"
@@ -867,6 +868,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);
@@ -1805,6 +1810,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:
@@ -1815,6 +1825,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:
@@ -3187,13 +3202,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)
+    cp_add_using_directive (processing_current_namespace,
+			    strlen (previous_namespace),
+			    strlen (processing_current_namespace));
+
   if (die->has_children)
     {
       struct die_info *child_die = die->next;
@@ -3204,6 +3265,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
@@ -5668,6 +5731,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.  */
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;
 
--- /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]