]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2002-10-09 David Carlton <carlton@math.stanford.edu>
authorDavid Carlton <carlton@bactrian.org>
Wed, 9 Oct 2002 23:08:10 +0000 (23:08 +0000)
committerDavid Carlton <carlton@bactrian.org>
Wed, 9 Oct 2002 23:08:10 +0000 (23:08 +0000)
* cp-support.c: Comment out cp_find_last_component and
cp_locate_arguments.
Add comments warning about pitfals involving demangled names.
* buildsym.c (finish_block): Grab the namespace names from the
front instead of from the back.
* Makefile.in (cp-support.o): Depend on gdb_assert_h.
* cp-support.c: #include "gdb_assert.h"
* cp-support.h: Declare cp_find_first_component.
* cp-support.c (cp_find_first_component): New function.
* buildsym.c (finish_block): Don't add namespace using stuff
unless there's a demangled name to work with.
(finish_block): Delete unused variable 'j'.
(finish_block): Move declaration of iter earlier to pacify GCC.

2002-10-08  David Carlton  <carlton@math.stanford.edu>

* symfile.c (obsavestring): Make first argument a const char *.
* symfile.h: Add opaque declaration for 'struct obstack'.
Make obsavestring take a const char * as its first argument.
* Makefile.in (cp-support.o): Correct dependencies.
* cp-support.h: Declare cp_add_using.
* cp-support.c: #include "gdb_obstack.h"
(cp_add_using): New function.
* Makefile.in (buildsym.o): Depend on $(cp_support_h).
* buildsym.c (finish_block): Add 'using' directives for
functions.
#include "cp-support.h"
* cp-support.h: Add function declarations.
* cp-support.c (cp_locate_arguments): New function.
(cp_find_last_component): New function.
* symtab.h (struct block): Add comment.

gdb/ChangeLog
gdb/Makefile.in
gdb/buildsym.c
gdb/cp-support.c
gdb/cp-support.h
gdb/symfile.c
gdb/symfile.h
gdb/symtab.h

index da709ab836a6bd746c7d3f76d6ecc27ebe287f07..1054705a551a74f0905980144af98569775e213d 100644 (file)
@@ -1,3 +1,37 @@
+2002-10-09  David Carlton  <carlton@math.stanford.edu>
+
+       * cp-support.c: Comment out cp_find_last_component and
+       cp_locate_arguments.
+       Add comments warning about pitfals involving demangled names.
+       * buildsym.c (finish_block): Grab the namespace names from the
+       front instead of from the back.
+       * Makefile.in (cp-support.o): Depend on gdb_assert_h.
+       * cp-support.c: #include "gdb_assert.h"
+       * cp-support.h: Declare cp_find_first_component.
+       * cp-support.c (cp_find_first_component): New function.
+       * buildsym.c (finish_block): Don't add namespace using stuff
+       unless there's a demangled name to work with.
+       (finish_block): Delete unused variable 'j'.
+       (finish_block): Move declaration of iter earlier to pacify GCC.
+
+2002-10-08  David Carlton  <carlton@math.stanford.edu>
+
+       * symfile.c (obsavestring): Make first argument a const char *.
+       * symfile.h: Add opaque declaration for 'struct obstack'.
+       Make obsavestring take a const char * as its first argument.
+       * Makefile.in (cp-support.o): Correct dependencies.
+       * cp-support.h: Declare cp_add_using.
+       * cp-support.c: #include "gdb_obstack.h"
+       (cp_add_using): New function.
+       * Makefile.in (buildsym.o): Depend on $(cp_support_h).
+       * buildsym.c (finish_block): Add 'using' directives for
+       functions.
+       #include "cp-support.h"
+       * cp-support.h: Add function declarations.
+       * cp-support.c (cp_locate_arguments): New function.
+       (cp_find_last_component): New function.
+       * symtab.h (struct block): Add comment.
+
 2002-10-07  David Carlton  <carlton@math.stanford.edu>
 
        * buildsym.c (finish_block): Initialize BLOCK_USING to NULL.
index 4a66d63bbcf2e753695e452340c0fa4c07e1aebf..96d0298e97f6459740a4b1000cda2c5fcfaf78d5 100644 (file)
@@ -1542,7 +1542,7 @@ buildsym.o: buildsym.c $(defs_h) $(bfd_h) $(gdb_obstack_h) $(symtab_h) \
        $(symfile_h) $(objfiles_h) $(gdbtypes_h) $(complaints_h) \
        $(gdb_string_h) $(expression_h) $(language_h) $(bcache_h) \
        $(filenames_h) $(macrotab_h) $(demangle_h) $(buildsym_h) \
-       $(stabsread_h) $(dictionary_h) $(gdb_assert_h)
+       $(stabsread_h) $(dictionary_h) $(gdb_assert_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) \
@@ -1587,7 +1587,8 @@ corelow.o: corelow.c $(defs_h) $(gdb_string_h) $(frame_h) $(inferior_h) \
        $(symtab_h) $(command_h) $(bfd_h) $(target_h) $(gdbcore_h) \
        $(gdbthread_h) $(regcache_h) $(symfile_h)
 cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_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_obstack_h) $(gdb_assert_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 3da29f81c201291a1e3037eaffa9e6a3fec39abf..612f6994a56cecec8174c956c500e1c1b4ae9ff3 100644 (file)
@@ -30,7 +30,7 @@
 #include "bfd.h"
 #include "gdb_obstack.h"
 #include "symtab.h"
-#include "symfile.h"           /* Needed for "struct complaint" */
+#include "symfile.h"           /* Needed for "struct complaint", obsavestring */
 #include "objfiles.h"
 #include "gdbtypes.h"
 #include "complaints.h"
@@ -43,6 +43,7 @@
 #include "demangle.h"          /* Needed by SYMBOL_INIT_DEMANGLED_NAME.  */
 #include "dictionary.h"
 #include "gdb_assert.h"
+#include "cp-support.h"
 /* Ask buildsym.h to define the vars it normally declares `extern'.  */
 #define        EXTERN
 /**/
@@ -234,7 +235,6 @@ finish_block (struct symbol *symbol, struct pending **listhead,
   register struct block *block;
   register struct pending_block *pblock;
   struct pending_block *opblock;
-  register int j;
 
   /* Initialize the block's dictionary.  */
 
@@ -266,9 +266,9 @@ finish_block (struct symbol *symbol, struct pending **listhead,
   if (symbol)
     {
       struct type *ftype = SYMBOL_TYPE (symbol);
+      struct dict_iterator iter;
       SYMBOL_BLOCK_VALUE (symbol) = block;
       BLOCK_FUNCTION (block) = symbol;
-      struct dict_iterator iter;
 
       if (TYPE_NFIELDS (ftype) <= 0)
        {
@@ -349,6 +349,36 @@ finish_block (struct symbol *symbol, struct pending **listhead,
                }
            }
        }
+
+      /* If we're in the C++ case, make sure that we add 'using'
+        directives for all of the namespaces in which this function
+        lives.  Also, make sure that the name was originally mangled:
+        if not, there certainly isn't any namespace information to
+        worry about!  (Also, if not, the gdb_assert will fail.)  */
+      if (SYMBOL_LANGUAGE (symbol) == language_cplus
+         && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL)
+       {
+         const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol);
+         const char *next;
+
+         for (next = cp_find_first_component (name);
+              *next == ':';
+              /* The '+ 2' is to skip the '::'.  */
+              next = cp_find_first_component (next + 2))
+           {
+             const char *namespace_name
+               = obsavestring (name, next - name,
+                               &objfile->symbol_obstack);
+             BLOCK_USING (block)
+               = cp_add_using ("", namespace_name, BLOCK_USING (block),
+                               &objfile->symbol_obstack);
+           }
+
+         /* FIMXE: carlton/2002-10-09: Until I understand the
+            possible pitfalls of demangled names a lot better, I want
+            to make sure I'm not running into surprises.  */
+         gdb_assert (*next == '\0');
+       }
     }
   else
     {
index 46363a8b3bf0a419d34c23e8c0f5d75953ff820a..1c7fcf1828d4fb26db75ee3c8d7a81c23e4a2f33 100644 (file)
 #include "cp-support.h"
 #include "gdb_string.h"
 #include "demangle.h"
+#include "gdb_obstack.h"
+#include "gdb_assert.h"
+
+/* 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, I suppose) class method, in which case it ends with
+     "const".
+
+   - 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?).  */
+
+/* FIXME: carlton/2002-10-09: Do all the functions here 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 +169,212 @@ method_name_from_physname (const char *physname)
   xfree (demangled_name);
   return ret;
 }
+
+#if 0
+
+/* FIXME: carlton/2002-10-09: cp_locate_arguments and
+   cp_find_last_component are broken: they don't deal with operator<<
+   and the like.  Oops.  I decided to fix this by starting from the
+   front, leading to cp_find_first_component (which may or may not be
+   correct...); if I don't find other uses for cp_locate_arguments and
+   cp_find_last_component soon, I'll delete them.  */
+
+/* Given a name that may or may not be the demangled name of a
+   function or method, this returns a pointer to the last character
+   that isn't part of the arguments, if there are any.  I.e. given a
+   pointer to "foo", it returns a pointer to the trailing '\0'; given
+   a pointer to "C::foo() const", it returns a pointer to the '('.  */
+
+const char *
+cp_locate_arguments (const char *name)
+{
+/* NOTE: carlton/2002-10-08: we search from the front rather than from
+   the back to avoid getting screwed up by the 'const' on the end.
+   ARGSOK says when a parenthesis should be the start of the arguments
+   to a function: otherwise, we get screwed up by 'A::(anonymous
+   namespace)::foo' and its ilk.  */
+
+  const char *current = name;
+  const char *end = name + strlen(name);
+  /* The nesting depth.  */
+  int depth = 0;
+  /* Might a parenthesis be the start of arguments?  */
+  int argsok = 0;
+
+  while (current < end)
+    {
+      switch (*current)
+       {
+       case '(':
+         if (depth == 0 && argsok)
+           return current;
+         ++depth;
+         argsok = 0;
+         break;
+       case '<':
+         ++depth;
+         argsok = 0;
+         break;
+       case ')':
+       case '>':
+         --depth;
+         argsok = 1;
+         break;
+       case ':':
+         argsok = 0;
+         break;
+       default:
+         argsok = 1;
+         break;
+       }
+      ++current;
+    }
+
+  return current;
+}
+
+/* Given pointers FIRST and LAST such that [FIRST,LAST) is a substring
+   of a demangled name, not including the arguments (i.e. call
+   cp_locate_arguments first!), this returns a pointer to the
+   beginning of the end of the last component.  For example, given
+   either "A::B::C::foo" or "foo", it returns a pointer to 'f'.  */
+
+/* FIXME: carlton/2002-10-08: This overlaps dreadfully with
+   find_last_component.  Sigh.  */
+
+const char *
+cp_find_last_component (const char *first, const char *last)
+{
+  const char *current;
+  int depth;
+
+  for (current = last - 1, depth = 0;
+       current >= first;
+       --current)
+    {
+      switch (*current)
+       {
+       case '(':
+       case '<':
+         --depth;
+         break;
+       case ')':
+       case '>':
+         ++depth;
+         break;
+       case ':':
+         if (depth == 0)
+           return current + 1;
+         break;
+       default:
+         break;
+       }
+    }
+
+  return first;
+}
+
+#endif /* 0 */
+
+/* This allocates a new using_data structure initialized to contain
+   OUTER and INNER, and puts it at the beginning of the linked list
+   given by NEXT.  It returns the resulting struct using_data_node.
+   All memory is allocated using OBSTACK.  */
+struct using_data_node *
+cp_add_using (const char *outer, const char *inner,
+             struct using_data_node *next,
+             struct obstack *obstack)
+{
+  struct using_data *current
+    = obstack_alloc (obstack, sizeof (struct using_data));
+  struct using_data_node *retval
+    = obstack_alloc (obstack, sizeof (struct using_data_node));
+
+  current->outer = outer;
+  current->inner = inner;
+  retval->current = current;
+  retval->next = next;
+
+  return retval;
+}
+
+/* This returns the first component of NAME, which should be the
+   demangled name of a C++ variable/function/method/etc.
+   Specifically, it returns a pointer to the first colon forming the
+   boundary of the first component: so, given 'A::foo' or 'A::B::foo'
+   it returns a pointer to the first :, and given 'foo', it returns a
+   pointer to the trailing '\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 '>'.  */
+
+/* Let's optimize away calls to strlen("operator").  */
+
+#define LENGTH_OF_OPERATOR 8
+
+const char *
+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.  */
+
+  if (strncmp (name, "operator", LENGTH_OF_OPERATOR) == 0)
+    {
+      name += LENGTH_OF_OPERATOR;
+      switch (*name)
+       {
+       case '<':
+         if (name[1] == '<')
+           name += 2;
+         else
+           name += 1;
+         break;
+       case '>':
+       case '-':
+         if (name[1] == '>')
+           name +=2;
+         else
+           name += 1;
+         break;
+       case '(':
+         name += 2;
+         break;
+       default:
+         name += 1;
+         break;
+       }
+    }
+
+  for (;; ++name)
+    {
+      switch (*name)
+       {
+       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'.)  */
+         for (name = cp_find_first_component (name + 1);
+              *name != '>';
+              name = cp_find_first_component (name + 2))
+           gdb_assert (*name == ':');
+         break;
+       case '(':
+         /* Similar comment as to '<'.  */
+         for (name = cp_find_first_component (name + 1);
+              *name != ')';
+              name = cp_find_first_component (name + 2))
+           gdb_assert (*name == ':');
+         break;
+       case '>':
+       case ')':
+       case '\0':
+       case ':':
+         return name;
+       default:
+         break;
+       }
+    }
+}
index 11f7b0a58f2b4dc427fe3967fe463d62b95077c4..c9ea966fed37438ab0f288fd1d4b71e7357c001a 100644 (file)
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+/* Opaque declarations.  */
+
+struct obstack;
+
 extern char *class_name_from_physname (const char *physname);
 
 extern char *method_name_from_physname (const char *physname);
 
+extern const char *cp_locate_arguments (const char *name);
+
+extern const char *cp_find_last_component (const char *first,
+                                          const char *last);
+
+extern const char *cp_find_first_component (const char *name);
+
 /* This is a struct to store data from "using directives" and similar
-   language constructs.  It contains two strings, OLD and NEW; both
-   should be fully-qualified namespace names, NEW should be an initial
-   substring of OLD, and it says that names in the namespace OLD
-   should be imported into namespace NEW.  For example, if it is used
-   to represent the directive "using namespace std;" then OLD should
-   be "std" and new should be "".  For a more complicated example, if
-   there is an anonymous namespace with a named namespace A, then OLD
-   should be "A::(anonymous namespace)" and new should be "A".  */
+   language constructs.  It contains two strings, OUTER and INNER;
+   both should be fully-qualified namespace names, OUTER should be an
+   initial substring of INNER, and it says that names in the namespace
+   INNER should be imported into namespace OUTER.  For example, if it
+   is used to represent the directive "using namespace std;" then
+   INNER should be "std" and new should be "".  For a more complicated
+   example, if there is an anonymous namespace with a named namespace
+   A, then INNER should be "A::(anonymous namespace)" and new should
+   be "A".  */
 
 /* FIXME: carlton/2002-10-07: That anonymous namespace example isn't
    that great, since it really depends not only on what the
@@ -43,8 +55,8 @@ extern char *method_name_from_physname (const char *physname);
 
 struct using_data
 {
-  const char *old;
-  const char *new;
+  const char *outer;
+  const char *inner;
 };
 
 /* This is a struct for a linked list of using_data's.  */
@@ -54,3 +66,8 @@ struct using_data_node
   struct using_data *current;
   struct using_data_node *next;
 };
+
+extern struct using_data_node *cp_add_using (const char *outer,
+                                            const char *inner,
+                                            struct using_data_node *next,
+                                            struct obstack *obstack);
index 3387b77032865e9f717289a32f6e6f9ad96c7452..6d794d57ffce7f95bea449740c2ba1af97cda601 100644 (file)
@@ -267,16 +267,16 @@ sort_pst_symbols (struct partial_symtab *pst)
    may be part of a larger string and we are only saving a substring. */
 
 char *
-obsavestring (char *ptr, int size, struct obstack *obstackp)
+obsavestring (const char *ptr, int size, struct obstack *obstackp)
 {
   register char *p = (char *) obstack_alloc (obstackp, size + 1);
   /* Open-coded memcpy--saves function call time.  These strings are usually
      short.  FIXME: Is this really still true with a compiler that can
      inline memcpy? */
   {
-    register char *p1 = ptr;
+    register const char *p1 = ptr;
     register char *p2 = p;
-    char *end = ptr + size;
+    const char *end = ptr + size;
     while (p1 != end)
       *p2++ = *p1++;
   }
index 8c8fae5dd15675075dbd312d7cebb502082f7f2c..fd4347c1f98e0491f009f8b3d7032f78f1646d0c 100644 (file)
 
 /* This file requires that you first include "bfd.h".  */
 
+/* Opaque declarations.  */
+
+struct obstack;
+
 /* Partial symbols are stored in the psymbol_cache and pointers to them
    are kept in a dynamically grown array that is obtained from malloc and
    grown as necessary via realloc.  Each objfile typically has two of these,
@@ -202,7 +206,7 @@ extern struct partial_symtab *start_psymtab_common (struct objfile *,
    (and add a null character at the end in the copy).
    Returns the address of the copy.  */
 
-extern char *obsavestring (char *, int, struct obstack *);
+extern char *obsavestring (const char *, int, struct obstack *);
 
 /* Concatenate strings S1, S2 and S3; return the new string.
    Space is found in the symbol_obstack.  */
index d73fc2439ec3a79a137e35bfbe633587718bc590..2d747f0703c6c0129f29da0578313f63b413c048 100644 (file)
@@ -405,7 +405,9 @@ struct block
     struct
     {
       /* Contains information about what using directives or other
-        similar features are added by this block.  */
+        similar features are added by this block.  This should always
+        be NULL for global blocks: if there are using directives that
+        affect an entire file, put it in the static block.  */
       struct using_data_node *using;
     }
     cplus_specific;