This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [rfa] annotate blocks with C++ namespace information
- From: Elena Zannoni <ezannoni at redhat dot com>
- To: David Carlton <carlton at math dot stanford dot edu>
- Cc: gdb-patches at sources dot redhat dot com, Daniel Jacobowitz <drow at mvista dot com>, Elena Zannoni <ezannoni at redhat dot com>, Jim Blandy <jimb at redhat dot com>
- Date: Mon, 14 Apr 2003 15:27:05 -0400
- Subject: Re: [rfa] annotate blocks with C++ namespace information
- References: <ro165rd2iiw.fsf@jackfruit.Stanford.EDU><20030311171133.GA3362@nevyn.them.org><ro13cllei8e.fsf@jackfruit.Stanford.EDU>
David Carlton writes:
> Just for reference, here's a slightly updated version of my namespace
> patch, following Daniel's suggestions. The only real change is that
> it adds a new command "maint cplus first_component" and a new file
> gdb.c++/maint.exp to test it.
Ok, I got around to this finally. It is basically ok, except for the
line between what is c++ and what is symbol table stuff. I think that
more stuff can be pushed into cp-support.c. See below...
>
> David Carlton
> carlton at math dot stanford dot edu
>
> 2003-03-17 David Carlton <carlton at math dot stanford dot edu>
>
> * Makefile.in (block.o): Depend on gdb_obstack_h and
> cp_support_h.
> (buildsym.o): Depend on cp_support_h.
> (cp-support.o): Depend on gdb_string_h, demangle_h, gdb_assert_h,
> gdb_obstack_h, symtab_h, symfile_h, and gdbcmd_h.
> * jv-lang.c (get_java_class_symtab): Set BLOCK_NAMESPACE.
> * dwarf2read.c (process_die): Set processing_has_namespace_info,
> processing_current_namespace.
> (read_namespace): Update processing_current_namespace; check for
> anonymous namespaces.
> (dwarf2_name): New function.
> (dwarf2_extension): Ditto.
> * cp-support.h: Update copyright, contributors.
> Add inclusion guards.
> Add opaque declaration for struct obstack.
> Add declarations for cp_find_first_component,
> cp_entire_prefix_len, cp_add_using, cp_copy_usings,
> cp_is_anonymous.
> (struct using_direct): New struct.
> * cp-support.c: Update copyright, contributors.
> Include gdb_assert.h, gdb_obstack.h, symtab.h, symfile.h,
> gdbcmd.h, ctype.h.
> New variable maint_cplus_cmd_list.
> (cp_find_first_component): New function.
> (cp_entire_prefix_len, cp_add_using, cp_copy_usings)
> (cp_is_anonymous, maint_cplus_command, first_component_command)
> (_initialize_cp_support): Ditto.
> * buildsym.h: New variables processing_has_namespace_info and
> processing_current_namespace.
> Declare add_using_directive.
> * buildsym.c: Include cp-support.h.
> New variable using_list.
> (add_symbol_to_list): Check for anonymous namespaces.
> (scan_for_anonymous_namespaces): New function.
> (add_using_directive): Ditto.
> (finish_block): Set block's scope.
> (start_symtab): Initialize processing_has_namespace_info and
> using_list.
> (end_symtab): Put the using list in the block.
> * block.h: Add opaque declarations for structs
> block_namespace_info, using_direct, and obstack.
> Add declarations for block_set_scope and block_set_using.
> (struct block): Add 'language_specific' member.
> (BLOCK_NAMESPACE): New macro.
> * block.c: Include gdb_obstack.h and cp-support.h.
> (struct block_namespace_info): New struct.
> (block_set_scope): New function.
> (block_set_using, block_initialize_namespace): Ditto.
>
> 2003-03-17 David Carlton <carlton at math dot stanford dot edu>
>
> * gdb.c++/maint.exp: New file.
>
> Index: Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/Makefile.in,v
> retrieving revision 1.341
> diff -u -p -r1.341 Makefile.in
> --- Makefile.in 5 Mar 2003 18:07:15 -0000 1.341
> +++ Makefile.in 17 Mar 2003 21:50:37 -0000
> @@ -1535,7 +1535,8 @@ ax-gdb.o: ax-gdb.c $(defs_h) $(symtab_h)
> $(regcache_h)
> ax-general.o: ax-general.c $(defs_h) $(ax_h) $(value_h) $(gdb_string_h)
> bcache.o: bcache.c $(defs_h) $(gdb_obstack_h) $(bcache_h) $(gdb_string_h)
> -block.o: block.c $(defs_h) $(block_h) $(symtab_h) $(symfile_h)
> +block.o: block.c $(defs_h) $(block_h) $(symtab_h) $(symfile_h) \
> + $(gdb_obstack_h) $(cp_support_h)
> blockframe.o: blockframe.c $(defs_h) $(symtab_h) $(bfd_h) $(symfile_h) \
> $(objfiles_h) $(frame_h) $(gdbcore_h) $(value_h) $(target_h) \
> $(inferior_h) $(annotate_h) $(regcache_h) $(gdb_assert_h) \
> @@ -1551,7 +1552,7 @@ buildsym.o: buildsym.c $(defs_h) $(bfd_h
> $(symfile_h) $(objfiles_h) $(gdbtypes_h) $(gdb_assert_h) \
> $(complaints_h) $(gdb_string_h) $(expression_h) $(language_h) \
> $(bcache_h) $(filenames_h) $(macrotab_h) $(demangle_h) $(buildsym_h) \
> - $(stabsread_h) $(block_h)
> + $(stabsread_h) $(block_h) $(cp_support_h)
> builtin-regs.o: builtin-regs.c $(defs_h) $(builtin_regs_h) $(gdbtypes_h) \
> $(gdb_string_h) $(gdb_assert_h)
> c-lang.o: c-lang.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(expression_h) \
> @@ -1596,7 +1597,9 @@ corelow.o: corelow.c $(defs_h) $(gdb_str
> $(gdbthread_h) $(regcache_h) $(symfile_h) $(readline_h)
> cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(command_h) \
> $(gdbcmd_h) $(ui_out_h) $(gdb_string_h)
> -cp-support.o: cp-support.c $(defs_h) $(cp_support_h)
> +cp-support.o: cp-support.c $(defs_h) $(cp_support_h) $(gdb_string_h) \
> + $(demangle_h) $(gdb_assert_h) $(gdb_obstack_h) $(symtab_h) \
> + $(symfile_h) $(gdbcmd_h)
> cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
> $(gdbtypes_h) $(expression_h) $(value_h) $(command_h) $(gdbcmd_h) \
> $(demangle_h) $(annotate_h) $(gdb_string_h) $(c_lang_h) $(target_h) \
> Index: jv-lang.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/jv-lang.c,v
> retrieving revision 1.15
> diff -u -p -r1.15 jv-lang.c
> --- jv-lang.c 25 Feb 2003 21:36:18 -0000 1.15
> +++ jv-lang.c 17 Mar 2003 21:52:04 -0000
> @@ -118,6 +118,7 @@ get_java_class_symtab (void)
> BLOCK_END (bl) = 0;
> BLOCK_FUNCTION (bl) = NULL;
> BLOCK_SUPERBLOCK (bl) = NULL;
> + BLOCK_NAMESPACE (bl) = NULL;
> BLOCK_GCC_COMPILED (bl) = 0;
> BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
>
> Index: dwarf2read.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/dwarf2read.c,v
> retrieving revision 1.88
> diff -u -p -r1.88 dwarf2read.c
> --- dwarf2read.c 25 Feb 2003 21:36:17 -0000 1.88
> +++ dwarf2read.c 17 Mar 2003 21:51:42 -0000
> @@ -853,6 +853,10 @@ static void process_die (struct die_info
>
> static char *dwarf2_linkage_name (struct die_info *);
>
> +static char *dwarf2_name (struct die_info *die);
> +
> +static struct die_info *dwarf2_extension (struct die_info *die);
> +
> static char *dwarf_tag_name (unsigned int);
>
> static char *dwarf_attr_name (unsigned int);
> @@ -1753,6 +1757,11 @@ process_die (struct die_info *die, struc
> case DW_TAG_common_inclusion:
> break;
> case DW_TAG_namespace:
> + if (!processing_has_namespace_info)
> + {
> + processing_has_namespace_info = 1;
> + processing_current_namespace = "";
> + }
> read_namespace (die, objfile, cu_header);
> break;
> case DW_TAG_imported_declaration:
> @@ -1763,6 +1772,11 @@ process_die (struct die_info *die, struc
> shouldn't in the C++ case, but conceivably could in the
> Fortran case, so we'll have to replace this gdb_assert if
> Fortran compilers start generating that info. */
> + if (!processing_has_namespace_info)
> + {
> + processing_has_namespace_info = 1;
> + processing_current_namespace = "";
> + }
> gdb_assert (!die->has_children);
> break;
> default:
> @@ -3157,13 +3171,59 @@ read_common_block (struct die_info *die,
>
> /* Read a C++ namespace. */
>
> -/* FIXME: carlton/2002-10-16: For now, we don't actually do anything
> - useful with the namespace data: we just process its children. */
> -
> static void
> read_namespace (struct die_info *die, struct objfile *objfile,
> const struct comp_unit_head *cu_header)
> {
> + const char *previous_namespace = processing_current_namespace;
> + const char *name = NULL;
> + int is_anonymous;
> + struct die_info *current_die;
> +
> + /* Loop through the extensions until we find a name. */
> +
> + for (current_die = die;
> + current_die != NULL;
> + current_die = dwarf2_extension (die))
> + {
> + name = dwarf2_name (current_die);
> + if (name != NULL)
> + break;
> + }
> +
> + /* Is it an anonymous namespace? */
> +
> + is_anonymous = (name == NULL);
> + if (is_anonymous)
> + name = "(anonymous namespace)";
> +
> + /* Now build the name of the current namespace. */
> +
> + if (previous_namespace[0] == '\0')
> + {
> + processing_current_namespace = name;
> + }
> + else
> + {
> + /* We need temp_name around because processing_current_namespace
> + is a const char *. */
> + char *temp_name = alloca (strlen (previous_namespace)
> + + 2 + strlen(name) + 1);
> + strcpy (temp_name, previous_namespace);
> + strcat (temp_name, "::");
> + strcat (temp_name, name);
> +
> + processing_current_namespace = temp_name;
> + }
> +
> + /* If it's an anonymous namespace that we're seeing for the first
> + time, add a using directive. */
> +
> + if (is_anonymous && dwarf_attr (die, DW_AT_extension) == NULL)
> + add_using_directive (processing_current_namespace,
> + strlen (previous_namespace),
> + strlen (processing_current_namespace));
> +
> if (die->has_children)
> {
> struct die_info *child_die = die->next;
> @@ -3174,6 +3234,8 @@ read_namespace (struct die_info *die, st
> child_die = sibling_die (child_die);
> }
> }
> +
> + processing_current_namespace = previous_namespace;
> }
>
> /* Extract all information from a DW_TAG_pointer_type DIE and add to
> @@ -5638,6 +5700,43 @@ dwarf2_linkage_name (struct die_info *di
> if (attr && DW_STRING (attr))
> return DW_STRING (attr);
> return NULL;
> +}
> +
> +/* Get name of a die, return NULL if not found. */
> +
> +static char *
> +dwarf2_name (struct die_info *die)
> +{
> + struct attribute *attr;
> +
> + attr = dwarf_attr (die, DW_AT_name);
> + if (attr && DW_STRING (attr))
> + return DW_STRING (attr);
> + return NULL;
> +}
> +
> +/* Return the die that this die in an extension of, or NULL if there
> + is none. */
> +
> +static struct die_info *
> +dwarf2_extension (struct die_info *die)
> +{
> + struct attribute *attr;
> + struct die_info *extension_die;
> + unsigned int ref;
> +
> + attr = dwarf_attr (die, DW_AT_extension);
> + if (attr == NULL)
> + return NULL;
> +
> + ref = dwarf2_get_ref_die_offset (attr);
> + extension_die = follow_die_ref (ref);
> + if (!extension_die)
> + {
> + error ("Dwarf Error: Cannot find referent at offset %d.", ref);
> + }
> +
> + return extension_die;
> }
>
> /* Convert a DIE tag into its string name. */
dwarf2read.c changes OK.
> Index: cp-support.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/cp-support.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 cp-support.h
> --- cp-support.h 14 Sep 2002 02:09:39 -0000 1.1
> +++ cp-support.h 17 Mar 2003 21:51:29 -0000
> @@ -1,7 +1,8 @@
> /* Helper routines for C++ support in GDB.
> - Copyright 2002 Free Software Foundation, Inc.
> + Copyright 2002, 2003 Free Software Foundation, Inc.
>
> Contributed by MontaVista Software.
> + Namespace support contributed by David Carlton.
>
> This file is part of GDB.
>
> @@ -20,6 +21,42 @@
> Foundation, Inc., 59 Temple Place - Suite 330,
> Boston, MA 02111-1307, USA. */
>
> +#ifndef CP_SUPPORT_H
> +#define CP_SUPPORT_H
> +
> +/* Opaque declarations. */
> +
> +struct obstack;
> +
> +/* This struct is designed to store data from using directives. It
> + says that names from namespace INNER should be visible within
> + namespace OUTER. OUTER should always be a strict initial substring
> + of INNER. These form a linked list; NEXT is the next element of
> + the list. */
> +
> +struct using_direct
> +{
> + char *inner;
> + char *outer;
> + struct using_direct *next;
> +};
> +
> extern char *class_name_from_physname (const char *physname);
>
> extern char *method_name_from_physname (const char *physname);
> +
> +extern unsigned int cp_find_first_component (const char *name);
> +
> +extern unsigned int cp_entire_prefix_len (const char *name);
> +
> +extern struct using_direct *cp_add_using (const char *name,
> + unsigned int inner_len,
> + unsigned int outer_len,
> + struct using_direct *next);
> +
> +extern struct using_direct *cp_copy_usings (struct using_direct *using,
> + struct obstack *obstack);
> +
> +extern int cp_is_anonymous (const char *namespace);
> +
> +#endif /* CP_SUPPORT_H */
> Index: cp-support.c
I am going to ignore this file, you and Daniel already settled it, right?
> ===================================================================
> RCS file: /cvs/src/src/gdb/cp-support.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 cp-support.c
> --- cp-support.c 14 Sep 2002 02:09:39 -0000 1.1
> +++ cp-support.c 17 Mar 2003 21:51:22 -0000
> @@ -1,7 +1,8 @@
> /* Helper routines for C++ support in GDB.
> - Copyright 2002 Free Software Foundation, Inc.
> + Copyright 2002, 2003 Free Software Foundation, Inc.
>
> Contributed by MontaVista Software.
> + Namespace support contributed by David Carlton.
>
> This file is part of GDB.
>
> @@ -21,9 +22,59 @@
> Boston, MA 02111-1307, USA. */
>
> #include "defs.h"
> +#include <ctype.h>
> #include "cp-support.h"
> #include "gdb_string.h"
> #include "demangle.h"
> +#include "gdb_assert.h"
> +#include "gdb_obstack.h"
> +#include "symtab.h"
> +#include "symfile.h"
> +#include "gdbcmd.h"
> +
> +/* The list of "maint cplus" commands. */
> +
> +static struct cmd_list_element *maint_cplus_cmd_list = NULL;
> +
> +/* The actual commands. */
> +
> +static void maint_cplus_command (char *arg, int from_tty);
> +static void first_component_command (char *arg, int from_tty);
> +
> +/* Here are some random pieces of trivia to keep in mind while trying
> + to take apart demangled names:
> +
> + - Names can contain function arguments or templates, so the process
> + has to be, to some extent recursive: maybe keep track of your
> + depth based on encountering <> and ().
> +
> + - Parentheses don't just have to happen at the end of a name: they
> + can occur even if the name in question isn't a function, because
> + a template argument might be a type that's a function.
> +
> + - Conversely, even if you're trying to deal with a function, its
> + demangled name might not end with ')': it could be a const or
> + volatile class method, in which case it ends with "const" or
> + "volatile".
> +
> + - Parentheses are also used in anonymous namespaces: a variable
> + 'foo' in an anonymous namespace gets demangled as "(anonymous
> + namespace)::foo".
> +
> + - And operator names can contain parentheses or angle brackets.
> + Fortunately, I _think_ that operator names can only occur in a
> + fairly restrictive set of locations (in particular, they have be
> + at depth 0, don't they?). */
> +
> +/* NOTE: carlton/2003-02-21: Daniel Jacobowitz came up with an example
> + where operator names don't occur at depth 0. Sigh. (It involved a
> + template argument that was a pointer: I hadn't realized that was
> + possible.) Handling such edge cases does not seem like a
> + high-priority problem to me. */
> +
> +/* FIXME: carlton/2003-03-13: We have several functions here with
> + overlapping functionality; can we combine them? Also, do they
> + handle all the above considerations correctly? */
>
> /* Find the last component of the demangled C++ name NAME. NAME
> must be a method name including arguments, in order to correctly
> @@ -138,4 +189,229 @@ method_name_from_physname (const char *p
>
> xfree (demangled_name);
> return ret;
> +}
> +
> +/* This returns the length of first component of NAME, which should be
> + the demangled name of a C++ variable/function/method/etc.
> + Specifically, it returns the index of the first colon forming the
> + boundary of the first component: so, given 'A::foo' or 'A::B::foo'
> + it returns the 1, and given 'foo', it returns 0. */
> +
> +/* Well, that's what it should do when called externally, but to make
> + the recursion easier, it also stops if it reaches an unexpected ')'
> + or '>'. */
> +
> +/* NOTE: carlton/2003-03-13: This function is currently only intended
> + for internal use: it's probably not entirely safe when called on
> + user-generated input, because some of the 'index += 2' lines might
> + go past the end of malformed input. */
> +
> +/* Let's optimize away calls to strlen("operator"). */
> +
> +#define LENGTH_OF_OPERATOR 8
> +
> +unsigned int
> +cp_find_first_component (const char *name)
> +{
> + /* Names like 'operator<<' screw up the recursion, so let's
> + special-case them. I _hope_ they can only occur at the start of
> + a component. */
> +
> + unsigned int index = 0;
> +
> + if (strncmp (name, "operator", LENGTH_OF_OPERATOR) == 0)
> + {
> + index += LENGTH_OF_OPERATOR;
> + while (isspace(name[index]))
> + ++index;
> + switch (name[index])
> + {
> + case '<':
> + if (name[index + 1] == '<')
> + index += 2;
> + else
> + index += 1;
> + break;
> + case '>':
> + case '-':
> + if (name[index + 1] == '>')
> + index += 2;
> + else
> + index += 1;
> + break;
> + case '(':
> + index += 2;
> + break;
> + default:
> + index += 1;
> + break;
> + }
> + }
> +
> + for (;; ++index)
> + {
> + switch (name[index])
> + {
> + case '<':
> + /* Template; eat it up. The calls to cp_first_component
> + should only return (I hope!) when they reach the '>'
> + terminating the component or a '::' between two
> + components. (Hence the '+ 2'.) */
> + index += 1;
> + for (index += cp_find_first_component (name + index);
> + name[index] != '>';
> + index += cp_find_first_component (name + index))
> + {
> + gdb_assert (name[index] == ':');
> + index += 2;
> + }
> + break;
> + case '(':
> + /* Similar comment as to '<'. */
> + index += 1;
> + for (index += cp_find_first_component (name + index);
> + name[index] != ')';
> + index += cp_find_first_component (name + index))
> + {
> + gdb_assert (name[index] == ':');
> + index += 2;
> + }
> + break;
> + case '>':
> + case ')':
> + case '\0':
> + case ':':
> + return index;
> + default:
> + break;
> + }
> + }
> +}
> +
> +/* If NAME is the fully-qualified name of a C++
> + function/variable/method/etc., this returns the length of its
> + entire prefix: all of the namespaces and classes that make up its
> + name. Given 'A::foo', it returns 1, given 'A::B::foo', it returns
> + 4, given 'foo', it returns 0. */
> +
> +unsigned int
> +cp_entire_prefix_len (const char *name)
> +{
> + unsigned int current_len = cp_find_first_component (name);
> + unsigned int previous_len = 0;
> +
> + while (name[current_len] != '\0')
> + {
> + gdb_assert (name[current_len] == ':');
> + previous_len = current_len;
> + /* Skip the '::'. */
> + current_len += 2;
> + current_len += cp_find_first_component (name + current_len);
> + }
> +
> + return previous_len;
> +}
> +
> +/* Create a new struct using direct whose inner namespace is the
> + initial substring of NAME of leng INNER_LEN and whose outer
> + namespace is the initial substring of NAME of length OUTER_LENGTH.
> + Set its next member in the linked list to NEXT; allocate all memory
> + using xmalloc. It copies the strings, so NAME can be a temporary
> + string. */
> +
> +struct using_direct *
> +cp_add_using (const char *name,
> + unsigned int inner_len,
> + unsigned int outer_len,
> + struct using_direct *next)
> +{
> + struct using_direct *retval;
> +
> + gdb_assert (outer_len < inner_len);
> +
> + retval = xmalloc (sizeof (struct using_direct));
> + retval->inner = savestring (name, inner_len);
> + retval->outer = savestring (name, outer_len);
> + retval->next = next;
> +
> + return retval;
> +}
> +
> +/* Make a copy of the using directives in the list pointed to by
> + USING, using OBSTACK to allocate memory. Free all memory pointed
> + to by USING via xfree. */
> +
> +extern struct using_direct *
> +cp_copy_usings (struct using_direct *using,
> + struct obstack *obstack)
> +{
> + if (using == NULL)
> + {
> + return NULL;
> + }
> + else
> + {
> + struct using_direct *retval
> + = obstack_alloc (obstack, sizeof (struct using_direct));
> + retval->inner = obsavestring (using->inner, strlen (using->inner),
> + obstack);
> + retval->outer = obsavestring (using->outer, strlen (using->outer),
> + obstack);
> + retval->next = cp_copy_usings (using->next, obstack);
> +
> + xfree (using->inner);
> + xfree (using->outer);
> + xfree (using);
> +
> + return retval;
> + }
> +}
> +
> +/* Test whether or not NAMESPACE looks like it mentions an anonymous
> + namespace; return nonzero if so. */
> +
> +int
> +cp_is_anonymous (const char *namespace)
> +{
> + return (strstr (namespace, "(anonymous namespace)")
> + != NULL);
> +}
> +
> +/* Don't allow just "maintenance cplus". */
> +
> +static void
> +maint_cplus_command (char *arg, int from_tty)
> +{
> + printf_unfiltered ("\"maintenance cplus\" must be followed by the name of a command.\n");
> + help_list (maint_cplus_cmd_list, "maintenance cplus ", -1, gdb_stdout);
> +}
> +
> +/* This is a front end for cp_find_first_component, for unit testing.
> + Be careful when using it: see the NOTE above
> + cp_find_first_component. */
> +
> +static void
> +first_component_command (char *arg, int from_tty)
> +{
> + int len = cp_find_first_component (arg);
> + char *prefix = alloca (len + 1);
> +
> + memcpy (prefix, arg, len);
> + prefix[len] = '\0';
> +
> + printf_unfiltered ("%s\n", prefix);
> +}
> +
> +void
> +_initialize_cp_support (void)
> +{
> + add_prefix_cmd ("cplus", class_maintenance, maint_cplus_command,
> + "C++ maintenance commands.", &maint_cplus_cmd_list,
> + "maintenance cplus ", 0, &maintenancelist);
> + add_alias_cmd ("cp", "cplus", class_maintenance, 1, &maintenancelist);
> +
> + add_cmd ("first_component", class_maintenance, first_component_command,
> + "Print the first class/namespace component of NAME.",
> + &maint_cplus_cmd_list);
> +
> }
> Index: buildsym.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/buildsym.h,v
> retrieving revision 1.11
> diff -u -p -r1.11 buildsym.h
> --- buildsym.h 20 Feb 2003 00:01:05 -0000 1.11
> +++ buildsym.h 17 Mar 2003 21:51:06 -0000
> @@ -85,6 +85,18 @@ EXTERN unsigned char processing_gcc_comp
>
> EXTERN unsigned char processing_acc_compilation;
>
> +/* When set, the file that we're processing seems to have debugging
> + info for C++ namespaces, so buildsym.c shouldn't try to guess
> + namespace info itself. */
> +
> +EXTERN unsigned char processing_has_namespace_info;
> +
> +/* If processing_has_namespace_info is nonzero, this string should
> + contain the name of the current namespace. The string is
> + temporary; copy it if you need it. */
> +
> +EXTERN const char *processing_current_namespace;
> +
> /* Count symbols as they are processed, for error messages. */
>
> EXTERN unsigned int symnum;
> @@ -228,6 +240,9 @@ extern void add_symbol_to_list (struct s
>
> extern struct symbol *find_symbol_in_list (struct pending *list,
> char *name, int length);
> +
> +extern void add_using_directive (const char *name, unsigned int outer_length,
> + unsigned int inner_length);
>
> extern void finish_block (struct symbol *symbol,
> struct pending **listhead,
> Index: buildsym.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/buildsym.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 buildsym.c
> --- buildsym.c 25 Feb 2003 21:36:17 -0000 1.31
> +++ buildsym.c 17 Mar 2003 21:51:00 -0000
> @@ -44,6 +44,8 @@
> #include "macrotab.h"
> #include "demangle.h" /* Needed by SYMBOL_INIT_DEMANGLED_NAME. */
> #include "block.h"
> +#include "cp-support.h"
> +
> /* Ask buildsym.h to define the vars it normally declares `extern'. */
> #define EXTERN
> /**/
> @@ -63,8 +65,15 @@ static struct pending *free_pendings;
> otherwise empty symtab from being tossed. */
>
> static int have_line_numbers;
> +
> +/* List of using directives that are active in the current file. */
> +
> +static struct using_direct *using_list;
> +
see below for some thoughts.....
>
> static int compare_line_numbers (const void *ln1p, const void *ln2p);
> +
> +static void scan_for_anonymous_namespaces (struct symbol *symbol);
>
>
> /* Initial sizes of data structures. These are realloc'd larger if
> @@ -91,7 +100,10 @@ add_free_pendings (struct pending *list)
> }
> }
>
> -/* Add a symbol to one of the lists of symbols. */
> +/* Add a symbol to one of the lists of symbols. While we're at it, if
> + we're in the C++ case and don't have full namespace debugging info,
> + check to see if it references an anonymous namespace; if so, add an
> + appropriate using directive. */
>
> void
> add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
> @@ -122,6 +134,61 @@ add_symbol_to_list (struct symbol *symbo
> }
>
> (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
> +
> + /* Check to see if we might need to look for a mention of anonymous
> + namespaces. */
> +
> + if (SYMBOL_LANGUAGE (symbol) == language_cplus
> + && !processing_has_namespace_info
> + && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
> + scan_for_anonymous_namespaces (symbol);
> +}
OK.
> +
> +/* Check to see if a symbol is contained within an anonymous
> + namespace; if so, add an appropriate using directive. */
> +
> +/* Optimize away strlen ("(anonymous namespace)"). */
> +
> +#define ANONYMOUS_NAMESPACE_LEN 21
> +
> +static void
> +scan_for_anonymous_namespaces (struct symbol *symbol)
> +{
> + const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
> + unsigned int previous_component;
> + unsigned int next_component;
> + const char *len;
> +
> + /* Start with a quick-and-dirty check for mention of "(anonymous
> + namespace)". */
> +
> + if (!cp_is_anonymous (name))
> + return;
> +
> + previous_component = 0;
> + next_component = cp_find_first_component (name + previous_component);
> +
> + while (name[next_component] == ':')
> + {
> + if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN
> + && strncmp (name + previous_component,
> + "(anonymous namespace)",
> + ANONYMOUS_NAMESPACE_LEN) == 0)
> + {
> + /* We've found a component of the name that's an anonymous
> + namespace. So add symbols in it to the namespace given
> + by the previous component if there is one, or to the
> + global namespace if there isn't. */
> + add_using_directive (name,
> + previous_component == 0
> + ? 0 : previous_component - 2,
> + next_component);
> + }
> + /* The "+ 2" is for the "::". */
> + previous_component = next_component + 2;
> + next_component = (previous_component
> + + cp_find_first_component (name + previous_component));
> + }
> }
>
Should this function be in cp-support.c? You could tighten the
interface a bit, by passing in the name of the symbol only, instead of
the symbol. This way it would definitely belong in cp-support.c (...dirty
plan to delegate c++ stuff to Daniel in an inequivocable manner..).
> /* Find a symbol named NAME on a LIST. NAME need not be
> @@ -149,6 +216,34 @@ find_symbol_in_list (struct pending *lis
> return (NULL);
> }
>
> +/* Add a using directive to using_list. NAME is the start of a string
> + that should contain the namespaces we want to add as initial
> + substrings, OUTER_LENGTH is the end of the outer namespace, and
> + INNER_LENGTH is the end of the inner namespace. If the using
> + directive in question has already been added, don't add it
> + twice. */
> +
> +void
> +add_using_directive (const char *name, unsigned int outer_length,
> + unsigned int inner_length)
> +{
> + struct using_direct *current;
> + struct using_direct *new;
> +
> + /* Has it already been added? */
> +
> + for (current = using_list; current != NULL; current = current->next)
> + {
> + if ((strncmp (current->inner, name, inner_length) == 0)
> + && (strlen (current->inner) == inner_length)
> + && (strlen (current->outer) == outer_length))
> + return;
> + }
> +
> + using_list = cp_add_using (name, inner_length, outer_length,
> + using_list);
> +}
> +
This too, could be in cp-support.c, it has no knowledge of symbols,
etc. Hmm, but it touches using_list. Which opens the question of
whether using_list should be in cp-support.c as well, so that the
interface is just using-list, exported in cp-support.h. It would
certainly make things cleaner. Not to mention that then you can check
stuff in w/o waiting for me. The struct using_direct could also be
made opaque, I think.
> /* At end of reading syms, or in case of quit, really free as many
> `struct pending's as we can easily find. */
>
> @@ -280,6 +375,7 @@ finish_block (struct symbol *symbol, str
> BLOCK_END (block) = end;
> /* Superblock filled in when containing block is made */
> BLOCK_SUPERBLOCK (block) = NULL;
> + BLOCK_NAMESPACE (block) = NULL;
>
> BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
>
> @@ -372,6 +468,41 @@ finish_block (struct symbol *symbol, str
> }
> }
> }
> +
> + /* If we're in the C++ case, record the namespace that the
> + function was defined in. Make sure that the name was
> + originally mangled: if not, there certainly isn't any
> + namespace information to worry about! */
> + if (SYMBOL_LANGUAGE (symbol) == language_cplus
> + && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
> + {
> + if (processing_has_namespace_info)
> + {
> + block_set_scope
> + (block, obsavestring (processing_current_namespace,
> + strlen (processing_current_namespace),
> + &objfile->symbol_obstack),
> + &objfile->symbol_obstack);
> + }
> + else
> + {
> + /* Try to figure out the appropriate namespace from the
> + demangled name. */
> +
> + /* FIXME: carlton/2003-02-21: If the function in
> + question is a method of a class, the name will
> + actually include the name of the class as well. This
> + should be harmless, but is a little unfortunate. */
> +
> + const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
> + unsigned int prefix_len = cp_entire_prefix_len (name);
> +
> + block_set_scope (block,
> + obsavestring (name, prefix_len,
> + &objfile->symbol_obstack),
> + &objfile->symbol_obstack);
> + }
> + }
> }
> else
> {
> @@ -803,6 +934,8 @@ start_symtab (char *name, char *dirname,
> global_symbols = NULL;
> within_function = 0;
> have_line_numbers = 0;
> + processing_has_namespace_info = 0;
> + using_list = NULL;
>
processing_has_namespace_info: there is one per symtab, yes?
I mean, it is set to 0 only here, just want to make sure.
> /* Context stack is initially empty. Allocate first one with room
> for 10 levels; reuse it forever afterward. */
> @@ -935,6 +1068,14 @@ end_symtab (CORE_ADDR end_addr, struct o
> finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
> objfile);
> blockvector = make_blockvector (objfile);
> + if (using_list != NULL)
> + {
> + block_set_using (BLOCKVECTOR_BLOCK (blockvector, STATIC_BLOCK),
> + cp_copy_usings (using_list,
Should this function be called something like cp_dup_usings? But you
are freeing the original copy, right? Why do you need to copy it over?
> + &objfile->symbol_obstack),
> + &objfile->symbol_obstack);
> + using_list = NULL;
If you move using_list in cp-support.c you could even introduce a
method that sets it to NULL, and another to check if it is
null. Nothing else would be needed, all other manipulations would be
done in cp-support.c.
> + }
> }
>
> #ifndef PROCESS_LINENUMBER_HOOK
> Index: block.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/block.h,v
> retrieving revision 1.2
> diff -u -p -r1.2 block.h
> --- block.h 20 Feb 2003 00:01:05 -0000 1.2
> +++ block.h 17 Mar 2003 21:50:53 -0000
> @@ -26,6 +26,9 @@
>
> struct symbol;
> struct symtab;
> +struct block_namespace_info;
> +struct using_direct;
> +struct obstack;
>
> /* All of the name-scope contours of the program
> are represented by `struct block' objects.
> @@ -74,6 +77,22 @@ struct block
>
> struct block *superblock;
>
> + /* Used for language-specific info. */
> +
> + union
> + {
> + struct
> + {
> + /* Contains information about namespace-related info relevant to
> + this block: using directives and the current namespace
> + scope. */
> +
> + struct block_namespace_info *namespace;
> + }
> + cplus_specific;
> + }
> + language_specific;
> +
> /* Version of GCC used to compile the function corresponding
> to this block, or 0 if not compiled with GCC. When possible,
> GCC should be compatible with the native compiler, or if that
> @@ -120,6 +139,7 @@ struct block
> #define BLOCK_FUNCTION(bl) (bl)->function
> #define BLOCK_SUPERBLOCK(bl) (bl)->superblock
> #define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
> +#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace
> #define BLOCK_HASHTABLE(bl) (bl)->hashtable
>
> /* For blocks without a hashtable (BLOCK_HASHTABLE (bl) == 0) only. */
> @@ -179,5 +199,12 @@ extern struct blockvector *blockvector_f
> extern struct block *block_for_pc (CORE_ADDR);
>
> extern struct block *block_for_pc_sect (CORE_ADDR, asection *);
> +
> +extern void block_set_scope (struct block *block, const char *scope,
> + struct obstack *obstack);
> +
> +extern void block_set_using (struct block *block,
> + struct using_direct *using,
> + struct obstack *obstack);
>
> #endif /* BLOCK_H */
> Index: block.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/block.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 block.c
> --- block.c 20 Feb 2003 00:01:05 -0000 1.2
> +++ block.c 17 Mar 2003 21:50:44 -0000
> @@ -23,6 +23,21 @@
> #include "block.h"
> #include "symtab.h"
> #include "symfile.h"
> +#include "gdb_obstack.h"
> +#include "cp-support.h"
> +
> +/* This is used by struct block to store namespace-related info for
> + C++ files, namely using declarations and the current namespace in
> + scope. */
> +
> +struct block_namespace_info
> +{
> + const char *scope;
> + struct using_direct *using;
> +};
> +
> +static void block_initialize_namespace (struct block *block,
> + struct obstack *obstack);
>
> /* Return Nonzero if block a is lexically nested within block b,
> or if a and b have the same pc range.
> @@ -138,4 +153,49 @@ struct block *
> block_for_pc (register CORE_ADDR pc)
> {
> return block_for_pc_sect (pc, find_pc_mapped_section (pc));
> +}
> +
> +/* Now come some functions designed to deal with C++ namespace
> + issues. */
> +
> +/* Set BLOCK's scope member to SCOPE; if needed, allocate memory via
> + OBSTACK. (It won't make a copy of SCOPE, however, so that already
> + has to be allocated correctly.) */
> +
> +void
> +block_set_scope (struct block *block, const char *scope,
> + struct obstack *obstack)
> +{
> + block_initialize_namespace (block, obstack);
> +
> + BLOCK_NAMESPACE (block)->scope = scope;
> +}
> +
> +/* Set BLOCK's using member to USING; if needed, allocate memory via
> + OBSTACK. (It won't make a copy of USING, however, so that already
> + has to be allocated correctly.) */
> +
> +void
> +block_set_using (struct block *block,
> + struct using_direct *using,
> + struct obstack *obstack)
> +{
> + block_initialize_namespace (block, obstack);
> +
> + BLOCK_NAMESPACE (block)->using = using;
> +}
> +
> +/* If BLOCK_NAMESPACE (block) is NULL, allocate it via OBSTACK and
> + ititialize its members to zero. */
> +
> +static void
> +block_initialize_namespace (struct block *block, struct obstack *obstack)
> +{
> + if (BLOCK_NAMESPACE (block) == NULL)
> + {
> + BLOCK_NAMESPACE (block)
> + = obstack_alloc (obstack, sizeof (struct block_namespace_info));
> + BLOCK_NAMESPACE (block)->scope = NULL;
> + BLOCK_NAMESPACE (block)->using = NULL;
> + }
> }
block.c changes OK.
The below is not my to approve.
> --- /dev/null Thu Apr 11 07:25:15 2002
> +++ maint.exp Mon Mar 17 13:33:14 2003
> @@ -0,0 +1,79 @@
> +# Copyright 2003 Free Software Foundation Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +
> +# Please email any bugs, comments, and/or additions to this file to:
> +# bug-gdb at prep dot ai dot mit dot edu
> +
> +
> +# This file tests C++-specific maintenance commands and help on those.
> +
> +# Currently, no source file is used.
> +
> +if $tracelevel then {
> + strace $tracelevel
> + }
> +
> +# Test the help messages.
> +
> +proc test_help {} {
> + gdb_test "help maintenance cplus" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
> +
> + gdb_test "help maint cp" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
> +
> + gdb_test "maint cp" "\"maintenance cplus\" must be followed by the name of a command.\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous."
> +
> + gdb_test "help maint cp first_component" "Print the first class/namespace component of NAME."
> +}
> +
> +# This is used when NAME should contain only a single component. Be
> +# careful to make sure that parentheses get escaped properly.
> +proc test_single_component {name} {
> + set matchname [string_to_regexp "$name"]
> + gdb_test "maint cp first_component $name" "$matchname"
> +}
> +
> +proc test_first_component {} {
> + test_single_component "foo"
> + test_single_component "operator<<"
> + test_single_component "operator>>"
> + test_single_component "operator ->"
> + test_single_component "operator()"
> + test_single_component "operator>"
> + test_single_component "operator<"
> + test_single_component "operator ->"
> + test_single_component "operator ->"
> +
> + test_single_component "foo()"
> + test_single_component "foo(int)"
> + test_single_component "foo(X::Y)"
> + test_single_component "foo(X::Y, A::B)"
> + test_single_component "foo(std::basic_streambuf<wchar_t,std::char_traits<wchar_t> >)"
> + test_single_component "operator>(X::Y)"
> +
> + gdb_test "maint cp first_component foo::bar" "foo"
> + gdb_test "maint cp first_component foo::bar::baz" "foo"
> + gdb_test "maint cp first_component C<A>::bar" "C<A>"
> + gdb_test "maint cp first_component C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >::bar" "C<std::basic_streambuf<wchar_t,std::char_traits<wchar_t> > >"
> +}
> +
> +gdb_exit
> +gdb_start
> +
> +test_help
> +test_first_component
> +
> +gdb_exit
> +return 0