From: David Carlton Date: Wed, 9 Oct 2002 23:08:10 +0000 (+0000) Subject: 2002-10-09 David Carlton X-Git-Tag: newlib-1_11_0~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=294d740dee4c0fbf215d94a7a5f6c043a5c8fbe2;p=thirdparty%2Fbinutils-gdb.git 2002-10-09 David Carlton * 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 * 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index da709ab836a..1054705a551 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,37 @@ +2002-10-09 David Carlton + + * 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 + + * 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 * buildsym.c (finish_block): Initialize BLOCK_USING to NULL. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 4a66d63bbcf..96d0298e97f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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) \ diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 3da29f81c20..612f6994a56 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -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 { diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 46363a8b3bf..1c7fcf1828d 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -24,6 +24,36 @@ #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; + } + } +} diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 11f7b0a58f2..c9ea966fed3 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -20,19 +20,31 @@ 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); diff --git a/gdb/symfile.c b/gdb/symfile.c index 3387b770328..6d794d57ffc 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -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++; } diff --git a/gdb/symfile.h b/gdb/symfile.h index 8c8fae5dd15..fd4347c1f98 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -25,6 +25,10 @@ /* 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. */ diff --git a/gdb/symtab.h b/gdb/symtab.h index d73fc2439ec..2d747f0703c 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -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;