From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18298 invoked by alias); 14 Apr 2003 19:22:55 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 18290 invoked from network); 14 Apr 2003 19:22:55 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sources.redhat.com with SMTP; 14 Apr 2003 19:22:55 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h3EJMsD02867 for ; Mon, 14 Apr 2003 15:22:54 -0400 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h3EJMsq05409 for ; Mon, 14 Apr 2003 15:22:54 -0400 Received: from localhost.redhat.com (romulus-int.sfbay.redhat.com [172.16.27.46]) by pobox.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h3EJMlI30722; Mon, 14 Apr 2003 15:22:48 -0400 Received: by localhost.redhat.com (Postfix, from userid 469) id 40C4E2C43F; Mon, 14 Apr 2003 15:27:06 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <16027.2953.467195.516437@localhost.redhat.com> Date: Mon, 14 Apr 2003 19:22:00 -0000 To: David Carlton Cc: gdb-patches@sources.redhat.com, Daniel Jacobowitz , Elena Zannoni , Jim Blandy Subject: Re: [rfa] annotate blocks with C++ namespace information In-Reply-To: References: <20030311171133.GA3362@nevyn.them.org> X-SW-Source: 2003-04/txt/msg00289.txt.bz2 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@math.stanford.edu > > 2003-03-17 David Carlton > > * 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 > > * 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 > #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@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