From 9219021cb5bab1206e80f84c2b4b7d8eac7eb4ea Mon Sep 17 00:00:00 2001 From: David Carlton Date: Tue, 15 Apr 2003 23:07:11 +0000 Subject: [PATCH] 2003-04-15 David Carlton * 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 * gdb.c++/maint.exp: New file. --- gdb/ChangeLog | 50 ++++++ gdb/Makefile.in | 15 +- gdb/block.c | 60 +++++++ gdb/block.h | 27 ++++ gdb/buildsym.c | 26 +++- gdb/cp-namespace.c | 266 ++++++++++++++++++++++++++++++++ gdb/cp-support.c | 209 ++++++++++++++++++++++++- gdb/cp-support.h | 58 ++++++- gdb/dwarf2read.c | 106 ++++++++++++- gdb/jv-lang.c | 1 + gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.c++/maint.exp | 79 ++++++++++ 12 files changed, 890 insertions(+), 11 deletions(-) create mode 100644 gdb/cp-namespace.c create mode 100644 gdb/testsuite/gdb.c++/maint.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9d04f92590..a83a8f5dd3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,53 @@ +2003-04-15 David Carlton + + * 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 * solib-svr4.c (svr4_have_link_map_offsets): New function. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index bb55a1d406..a78ef16099 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 8aa08fb175..7bfd866384 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 d7dbf31532..2fef52adc9 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 4c4ac9001c..d3c9ddfc17 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 0000000000..7205cf7383 --- /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 46363a8b3b..ca47854def 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 #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 a7d333f28b..76e842b5d1 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 b5fd38982f..32a9f44b56 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 #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 9e73030362..a44452b29b 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 853ca8ce00..e9dbd6217f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-04-15 David Carlton + + * gdb.c++/maint.exp: New file. + 2003-04-14 Elena Zannoni * 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 0000000000..6e1da97bd5 --- /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 >)" + 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::bar" "C" + gdb_test "maint cp first_component C > >::bar" "C > >" +} + +gdb_exit +gdb_start + +test_help +test_first_component + +gdb_exit +return 0 -- 2.34.1