From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17363 invoked by alias); 19 Jul 2010 15:28:39 -0000 Received: (qmail 17350 invoked by uid 22791); 19 Jul 2010 15:28:37 -0000 X-SWARE-Spam-Status: No, hits=-5.3 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BJ,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 19 Jul 2010 15:28:30 +0000 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o6JFSTMS008417 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 19 Jul 2010 11:28:29 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o6JFSSij013973 for ; Mon, 19 Jul 2010 11:28:29 -0400 Received: from [10.15.16.129] (dhcp-10-15-16-129.yyz.redhat.com [10.15.16.129]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id o6JFSSdY019766 for ; Mon, 19 Jul 2010 11:28:28 -0400 Message-ID: <4C446F1C.60507@redhat.com> Date: Mon, 19 Jul 2010 15:28:00 -0000 From: sami wagiaalla User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.10) Gecko/20100621 Fedora/3.0.5-1.fc13 Thunderbird/3.0.5 MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: [patch 1/3] Template Lookup Content-Type: multipart/mixed; boundary="------------040600000404040603070706" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-07/txt/msg00284.txt.bz2 This is a multi-part message in MIME format. --------------040600000404040603070706 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 984 Names of template symbols in debug info contains the full template parameters such as: foo(int) foo(char) while this is useful for differentiating various instances of template it provides unnatural user experience when you user tries to call these functions. For example: (gdb) print foo(1) (gdb) print foo('a') This patch removes the template parameters from the name and stores the cleaned name in a newly created variable 'search_name' in the -now obstack allocated- 'cplus_specific' structure. So now the user can do: (gdb) print foo(1) (gdb) print foo('a') The function choice is made by overload resolution as it should be. Functionality that required the fully qualified name still works. For example: (gdb) break foo This is because if the user included template parameters in the name then the template name is double checked for every hit. This series was tested by running the testsuit on Fedora 13 with gcc 4.4.4 on x8664. --------------040600000404040603070706 Content-Type: text/plain; name="template_lookup_1.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="template_lookup_1.patch" Content-length: 16155 Create search_name and fixed template lookup 2010-07-15 Sami Wagiaalla * valops.c (find_overload_match): Use SYMBOL_SEARCH_NAME instead of SYMBOL_NATURAL_NAME. * symtab.h: Added new member search_name to cplus_specific. (symbol_set_cplus_search_name): New function prototype. (symbol_get_cplus_search_name): New function prototype. * symtab.c (symbol_set_cplus_search_name): New function. (symbol_get_cplus_search_name): New function. (symbol_search_name): Handle the C++ case. (symbol_matches_template_name): New function. * dwarf2read.c (new_symbol): Set search_name of C++ template symbols. * cp-support.H (cp_name_has_template_parameters): New function prototype. (cp_remove_template_params): New function ptototype. * cp-support.c (cp_name_has_template_parameters): New function. (cp_remove_template_params_component): New function. (cp_remove_template_params): New function. (overload_list_add_symbol): Use SYMBOL_SEARCH_NAME instead of SYMBOL_NATURAL_NAME. * cp-name-parser.y (cp_demangled_name_to_comp): Added more detail to comment. 2010-07-15 Sami Wagiaalla * gdb.cp/temp-op.exp: New test. * gdb.cp/temp-op.cc: New test. * gdb.cp/cp-relocate.exp: Set the language C++. diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index 6d7b600..c9b5747 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1966,9 +1966,12 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len) &err); } -/* Convert a demangled name to a demangle_component tree. On success, - the root of the new tree is returned; it is valid until the next - call to this function and should not be freed. On error, NULL is +/* Convert a demangled name to a demangle_component tree. The structure + of the tree depends on the format of each node in the tree. For + information on the structure of a node see the comment corresponding + to its type in demangle_component_type. + On success, the root of the new tree is returned; it is valid until the + next call to this function and should not be freed. On error, NULL is returned, and an error message will be set in *ERRMSG (which does not need to be freed). */ diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 41af7ae..4ef1a0a 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -428,6 +428,72 @@ cp_remove_params (const char *demangled_name) return ret; } +/* Returns 1 if the given name contains template parameters; + otherwise return 0. + Used as a quick heuristic to avoid more expensive template + parsing when not necessary. */ + +int +cp_name_has_template_parameters (const char *name) +{ + char *c = strchr (name, '<'); + return c != NULL && strchr (c+1, '>') != NULL; +} + +/* Remove template parameters components from the give tree. */ + +static struct demangle_component * +cp_remove_template_params_component (struct demangle_component *comp) +{ + + gdb_assert (comp != NULL); + + switch (comp->type) + { + case DEMANGLE_COMPONENT_TEMPLATE: + /* If there is a template component remove this node by re-parenting the + the left child. */ + comp = d_left (comp); + break; + case DEMANGLE_COMPONENT_QUAL_NAME: + /* For a qualified name remove template components from the right + subtree. */ + d_right (comp) = cp_remove_template_params_component (d_right (comp)); + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + /* Template components, if present, will be in the left subtree. Remove + them. */ + d_left (comp) = cp_remove_template_params_component (d_left (comp)); + break; + default: + break; + } + + return comp; +} + +/* Remove template parameters from the given name. The returned string is + malloc'ed and must be properly saved and freed. */ + +char * +cp_remove_template_params (const char *name) +{ + struct demangle_component *ret_comp; + char *ret = NULL; + + if (name == NULL) + return NULL; + + ret_comp = cp_demangled_name_to_comp (name, NULL); + if (ret_comp == NULL) + return NULL; + + ret_comp = cp_remove_template_params_component (ret_comp); + ret = cp_comp_to_string (ret_comp, 10); + + return ret; +} + /* Here are some random pieces of trivia to keep in mind while trying to take apart demangled names: @@ -661,7 +727,7 @@ overload_list_add_symbol (struct symbol *sym, const char *oload_name) return; /* Get the demangled name without parameters */ - sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym)); + sym_name = cp_remove_params (SYMBOL_SEARCH_NAME (sym)); if (!sym_name) return; diff --git a/gdb/cp-support.h b/gdb/cp-support.h index ddc4c93..a2c8f7f 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -107,6 +107,10 @@ extern char *cp_func_name (const char *full_name); extern char *cp_remove_params (const char *demangled_name); +extern int cp_name_has_template_parameters (const char *name); + +extern char *cp_remove_template_params (const char *name); + extern struct symbol **make_symbol_overload_list (const char *, const char *); diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index a8692ea..e4abd23 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -8661,6 +8661,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) if (name) { const char *linkagename; + const char *search_name = NULL; sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol)); @@ -8680,6 +8681,26 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) (char *) dwarf2_full_name (name, die, cu), NULL); + /* For C++ if the name contains template parameters remove them, and set + the cleaned up name to be the search name. */ + if (cu->language == language_cplus && linkagename + && cp_name_has_template_parameters (linkagename)) + { + char *tmp = cp_remove_template_params (linkagename); + + if (tmp != NULL && strcmp (tmp, linkagename) != 0) + { + search_name = obsavestring (tmp, strlen (tmp), + &objfile->objfile_obstack); + + symbol_set_cplus_search_name (&sym->ginfo, + objfile, + search_name); + } + + xfree (tmp); + } + /* Default assumptions. Use the passed type or decode it from the die. */ SYMBOL_DOMAIN (sym) = VAR_DOMAIN; diff --git a/gdb/symtab.c b/gdb/symtab.c index 2232114..70feb62 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -389,6 +389,30 @@ symbol_get_demangled_name (const struct general_symbol_info *gsymbol) return gsymbol->language_specific.mangled_lang.demangled_name; } +/* Set the search name of the give GSYMBOL to name. */ +void +symbol_set_cplus_search_name (struct general_symbol_info *gsymbol, + struct objfile *objfile, + const char *name) +{ + if (gsymbol->language_specific.cplus_specific == NULL) + symbol_init_cplus_specific (gsymbol, objfile); + + gsymbol->language_specific.cplus_specific->search_name = (char *) name; +} + +/* Get the search name of the give GSYMBOL. */ + +char* +symbol_get_cplus_search_name (const struct general_symbol_info *gsymbol) +{ + if (gsymbol->language_specific.cplus_specific != NULL + && gsymbol->language_specific.cplus_specific->search_name != NULL) + return gsymbol->language_specific.cplus_specific->search_name; + + return symbol_natural_name (gsymbol); +} + /* Initialize the language dependent portion of a symbol depending upon the language for the symbol. */ @@ -753,6 +777,8 @@ symbol_search_name (const struct general_symbol_info *gsymbol) { if (gsymbol->language == language_ada) return gsymbol->name; + else if (gsymbol->language == language_cplus) + return symbol_get_cplus_search_name (gsymbol); else return symbol_natural_name (gsymbol); } @@ -1656,6 +1682,18 @@ find_main_filename (void) return (NULL); } +/* Return 1 if NAME matches SYM's template name. */ + +static int +symbol_matches_template_name (const char *name, struct symbol *sym) +{ + const char *template_name = SYMBOL_NATURAL_NAME(sym); + if (template_name == NULL) + return 0; + + return strcmp_iw (template_name, name) == 0; +} + /* Search BLOCK for symbol NAME in DOMAIN. Note that if NAME is the demangled form of a C++ symbol, we will fail @@ -1677,10 +1715,29 @@ lookup_block_symbol (const struct block *block, const char *name, if (!BLOCK_FUNCTION (block)) { + const char *template_name = NULL; + + if (current_language->la_language == language_cplus + && cp_name_has_template_parameters (name)) + { + template_name = name; + name = cp_remove_template_params (name); + + if (name == NULL) + /* Not a legal C++ name. */ + return NULL; + } + for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter); sym != NULL; sym = dict_iter_name_next (name, &iter)) { + /* For C++ if the name being searched for contains template + parameters check the template name of the symbol. */ + if (template_name != NULL + && !symbol_matches_template_name (template_name, sym)) + continue; + if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) return sym; diff --git a/gdb/symtab.h b/gdb/symtab.h index e6ab26f..d3d85cf 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -80,6 +80,11 @@ struct program_space; struct cplus_specific { char *demangled_name; + + /* If the symbol name contains template parameters this is the name with + these parameters removed to be used during search. Otherwise this + should be NULL, and the regular symbol name should be used. */ + char *search_name; }; /* Define a structure for the information that is common to all symbol types, @@ -166,6 +171,13 @@ extern void symbol_set_demangled_name (struct general_symbol_info *, char *, extern char *symbol_get_demangled_name (const struct general_symbol_info *); +/* Set the template name of the give GSYMBOL to name. */ +extern void symbol_set_cplus_search_name (struct general_symbol_info *gsymbol, + struct objfile *objfile, + const char *name); + +extern char* symbol_get_cplus_search_name (const struct general_symbol_info *); + extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); /* Note that all the following SYMBOL_* macros are used with the @@ -273,6 +285,7 @@ extern char *symbol_demangled_name (const struct general_symbol_info *symbol); (symbol_search_name (&(symbol)->ginfo)) extern char *symbol_search_name (const struct general_symbol_info *); + /* Analogous to SYMBOL_MATCHES_NATURAL_NAME, but uses the search name. */ #define SYMBOL_MATCHES_SEARCH_NAME(symbol, name) \ diff --git a/gdb/testsuite/gdb.cp/cp-relocate.exp b/gdb/testsuite/gdb.cp/cp-relocate.exp index 30d362a..880ad38 100644 --- a/gdb/testsuite/gdb.cp/cp-relocate.exp +++ b/gdb/testsuite/gdb.cp/cp-relocate.exp @@ -52,6 +52,8 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_file_cmd ${binfile} +gdb_test_no_output "set language c++" "" + # Find the interesting functions. We go to a little effort to find # the right function names here, to work around PR c++/40. set func1_name "" @@ -123,6 +125,8 @@ gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir +gdb_test_no_output "set language c++" "" + gdb_test "add-symbol-file ${binfile} 0 -s ${func1_sec} 0x10000 -s ${func2_sec} 0x20000" \ "Reading symbols from .*${testfile}\\.o\\.\\.\\.done\\.(|\r\nUsing host libthread_db library .*libthread_db.so.*\\.)" \ "add-symbol-file ${testfile}.o" \ diff --git a/gdb/testsuite/gdb.cp/temp-op.cc b/gdb/testsuite/gdb.cp/temp-op.cc new file mode 100644 index 0000000..6d4b13d --- /dev/null +++ b/gdb/testsuite/gdb.cp/temp-op.cc @@ -0,0 +1,105 @@ +class A +{ +}; + +template +int foo (T, char) +{ + T t; + return 11; +} + +template +int foo2 (T, T2, char) +{ + T t; + return 11; +} + +namespace C +{ + namespace D { + template + int foo3 (T, T2, char) + { + T t; + return 11; + } + } +} +int operator<< (A, int) +{ + return 12; +} + +int operator< (A, int) +{ + return 13; +} + +int operator<= (A, int) +{ + return 14; +} + +template +int operator==(T, char) +{ + return 15; +} + +int operator==(A, int) +{ + return 16; +} + +template +class B{ + T t; +public: + int operator==(int) + { + return 17; + } +}; + +int operator== (B, char){ + return 18; +} + +template +class Outer{ + public: + template + class Inner{ + public: + template + class ReallyInner{}; + }; +}; + + +int main () +{ + A a; + + foo (a, 'a'); + foo (a, 1); + foo2 (a, a, 'a'); + C::D::foo3 (a, a, 'a'); + + a << 22; + a < 22; + a <= 22; + + a == 'a'; + a == 1; + + B b; + b == 1; + b == 'a'; + + Outer::Inner::ReallyInner<5> oir; + + return 0; +} diff --git a/gdb/testsuite/gdb.cp/temp-op.exp b/gdb/testsuite/gdb.cp/temp-op.exp new file mode 100644 index 0000000..f48582f --- /dev/null +++ b/gdb/testsuite/gdb.cp/temp-op.exp @@ -0,0 +1,68 @@ +# Copyright 2008 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 3 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, see . + +if $tracelevel then { + strace $tracelevel +} + +set testfile temp-op +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +# Test that a templated function can be found +# with out specification of template arguments +gdb_test "p foo(a, 'a')" "= 11" + +# Test that function names with '<' in their names +# are not mistaken for templates +gdb_test "p a << 22" "= 12" +gdb_test "p a < 22" "= 13" +gdb_test "p a <= 22" "= 14" + +# Test that a template operator can be correctly +# evaluated +gdb_test "p a == 'a'" "= 15" + +# Test that overload resolution is still correctly +# performed. +gdb_test "p a == 1" "= 16" + +# Test calling a member function of a template class +gdb_test "p b == 1" "= 17" +gdb_test "p b == 'a'" "= 18" + +# Test that printing the a template name without +# template parameters does not return an arbitrary match + +gdb_test "p foo" "No symbol \"foo\" in current context" +gdb_test "ptype B" "No symbol \"foo\" in current context" diff --git a/gdb/valops.c b/gdb/valops.c index 506d40e..59ec3ee 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -2458,7 +2458,7 @@ find_overload_match (struct type **arg_types, int nargs, if (fsym) { - qualified_name = SYMBOL_NATURAL_NAME (fsym); + qualified_name = SYMBOL_SEARCH_NAME (fsym); /* If we have a function with a C++ name, try to extract just the function part. Do not try this for non-functions (e.g. --------------040600000404040603070706--