2003-04-15 David Carlton <carlton@math.stanford.edu>
authorDavid Carlton <carlton@bactrian.org>
Tue, 15 Apr 2003 23:07:11 +0000 (23:07 +0000)
committerDavid Carlton <carlton@bactrian.org>
Tue, 15 Apr 2003 23:07:11 +0000 (23:07 +0000)
* 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-04-15  David Carlton  <carlton@math.stanford.edu>

* gdb.c++/maint.exp: New file.

12 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/block.c
gdb/block.h
gdb/buildsym.c
gdb/cp-namespace.c [new file with mode: 0644]
gdb/cp-support.c
gdb/cp-support.h
gdb/dwarf2read.c
gdb/jv-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.c++/maint.exp [new file with mode: 0644]

index 9d04f9259017581046e5227451c81e330f69ee92..a83a8f5dd3fc393990753d8443b0aa7bda50147e 100644 (file)
@@ -1,3 +1,53 @@
+2003-04-15  David Carlton  <carlton@math.stanford.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-04-14  Kevin Buettner  <kevinb@redhat.com>
 
        * solib-svr4.c (svr4_have_link_map_offsets): New function.
index bb55a1d406ec829fe1accc980b2ab951990f8f9b..a78ef16099a517fe5828aabf41008c0456a0ac59 100644 (file)
@@ -512,7 +512,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
        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 breakpoint.o findvar.o regcache.o \
        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) $(symfile_h) $(gdbtypes_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) $(gdb_obstack_h) $(symtab_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_string_h) $(frame_h) $(inferior_h) \
        $(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) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
        $(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 8aa08fb175d68f9d311730a35db54499450e2878..7bfd866384860cc6010dedeb8fd8c67c04c2559f 100644 (file)
 #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.
@@ -139,3 +154,48 @@ 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 d7dbf315324bb3e725c9fab770ceda6692724d54..2fef52adc968f8748c1c1deee21a789337a25cb5 100644 (file)
@@ -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.  */
@@ -180,4 +200,11 @@ 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 4c4ac9001c13716d04bb85ed5c2d932efe15be5d..d3c9ddfc175b46e2c58fa53075bd5787f8eabc63 100644 (file)
@@ -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 *symbol, struct pending **listhead)
     }
 
   (*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, struct pending **listhead,
   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, struct pending **listhead,
                }
            }
        }
+
+      /* 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, CORE_ADDR start_addr)
     }
   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 objfile *objfile, int section)
       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
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
new file mode 100644 (file)
index 0000000..7205cf7
--- /dev/null
@@ -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 46363a8b3bf0a419d34c23e8c0f5d75953ff820a..ca47854def2add12c503c638bb72a5281d4929fd 100644 (file)
@@ -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.
 
    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
@@ -139,3 +186,163 @@ method_name_from_physname (const char *physname)
   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 a7d333f28b201b531e3e159c4f11c14fcdaf915d..76e842b5d1fb93d31b9d802bfc663878fccf56e4 100644 (file)
@@ -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.
 
    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 b5fd38982f3e670dadf074f450f23a529625fa90..32a9f44b566152f20d1830ecc8cd5dc56c9724aa 100644 (file)
@@ -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 *, struct objfile *,
 
 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, struct objfile *objfile,
     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, struct objfile *objfile,
         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, struct objfile *objfile,
 
 /* 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, struct objfile *objfile,
          child_die = sibling_die (child_die);
        }
     }
+
+  processing_current_namespace = previous_namespace;
 }
 
 /* Extract all information from a DW_TAG_pointer_type DIE and add to
@@ -5670,6 +5733,43 @@ dwarf2_linkage_name (struct die_info *die)
   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.  */
 
 static char *
index 9e73030362d1e11a004a55b380aed3d795fc6b51..a44452b29b5fdc547c3227e1cc503430cc22b806 100644 (file)
@@ -119,6 +119,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 853ca8ce000c568be513f04c09189887ab8b1de8..e9dbd6217fea844199a5e6e836e797f4a006ef2f 100644 (file)
@@ -1,3 +1,7 @@
+2003-04-15  David Carlton  <carlton@math.stanford.edu>
+
+       * gdb.c++/maint.exp: New file.
+
 2003-04-14  Elena Zannoni  <ezannoni@redhat.com>
 
        * gdb.threads/schedlock.c: Change type of thread function argument
diff --git a/gdb/testsuite/gdb.c++/maint.exp b/gdb/testsuite/gdb.c++/maint.exp
new file mode 100644 (file)
index 0000000..6e1da97
--- /dev/null
@@ -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@prep.ai.mit.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