summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog50
-rw-r--r--gdb/Makefile.in15
-rw-r--r--gdb/block.c60
-rw-r--r--gdb/block.h27
-rw-r--r--gdb/buildsym.c26
-rw-r--r--gdb/cp-namespace.c266
-rw-r--r--gdb/cp-support.c209
-rw-r--r--gdb/cp-support.h58
-rw-r--r--gdb/dwarf2read.c106
-rw-r--r--gdb/jv-lang.c1
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.c++/maint.exp79
12 files changed, 890 insertions, 11 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 9d04f925901..a83a8f5dd3f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bb55a1d406e..a78ef16099a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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)
diff --git a/gdb/block.c b/gdb/block.c
index 8aa08fb175d..7bfd8663848 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -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.
@@ -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;
+ }
+}
diff --git a/gdb/block.h b/gdb/block.h
index d7dbf315324..2fef52adc96 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -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 */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 4c4ac9001c1..d3c9ddfc175 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -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
index 00000000000..7205cf73838
--- /dev/null
+++ b/gdb/cp-namespace.c
@@ -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;
+ }
+}
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 46363a8b3bf..ca47854def2 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -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
@@ -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);
+
+}
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index a7d333f28b2..76e842b5d1f 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -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 */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index b5fd38982f3..32a9f44b566 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -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 *
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 9e73030362d..a44452b29b5 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -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;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 853ca8ce000..e9dbd6217fe 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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
index 00000000000..6e1da97bd52
--- /dev/null
+++ b/gdb/testsuite/gdb.c++/maint.exp
@@ -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