+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.
$(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) \
$(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) \
#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"
#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
/**/
register struct block *block;
register struct pending_block *pblock;
struct pending_block *opblock;
- register int j;
/* Initialize the block's dictionary. */
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)
{
}
}
}
+
+ /* 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
{
#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
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;
+ }
+ }
+}
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
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. */
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);
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++;
}
/* 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,
(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. */
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;