From: Keith Seitz Date: Tue, 21 Feb 2017 21:32:53 +0000 (-0800) Subject: Add a language method to hash symbol names for dictionary lookups. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eaed9d37278824ede2b058779fc54c710528ccb7;p=thirdparty%2Fbinutils-gdb.git Add a language method to hash symbol names for dictionary lookups. This patch does *not* address minsyms or gdb_index symbols. Pedro was looking into some of that on his cp-linespec branch. --- diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index fd9ac02e13b..e0e3204da24 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -14089,6 +14089,7 @@ const struct language_defn ada_language_defn = { c_get_string, ada_get_symbol_name_cmp, /* la_get_symbol_name_cmp */ ada_iterate_over_symbols, + default_compute_string_hash, &ada_varobj_ops, NULL, NULL, diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 76d74f89a0b..80a48e82b01 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -128,6 +128,9 @@ struct buildsym_compunit /* The compunit we are building. */ struct compunit_symtab *compunit_symtab; + + /* Language of this compunit_symtab. */ + enum language language; }; /* The work-in-progress of the compunit we are building. @@ -351,20 +354,23 @@ finish_block_internal (struct symbol *symbol, if (symbol) { - BLOCK_DICT (block) = dict_create_linear (&objfile->objfile_obstack, - *listhead); + BLOCK_DICT (block) + = dict_create_linear (&objfile->objfile_obstack, + buildsym_compunit->language, *listhead); } else { if (expandable) { - BLOCK_DICT (block) = dict_create_hashed_expandable (); + BLOCK_DICT (block) + = dict_create_hashed_expandable (buildsym_compunit->language); dict_add_pending (BLOCK_DICT (block), *listhead); } else { BLOCK_DICT (block) = - dict_create_hashed (&objfile->objfile_obstack, *listhead); + dict_create_hashed (&objfile->objfile_obstack, + buildsym_compunit->language, *listhead); } } @@ -768,7 +774,8 @@ start_subfile (const char *name) (or NULL if not known). */ static struct buildsym_compunit * -start_buildsym_compunit (struct objfile *objfile, const char *comp_dir) +start_buildsym_compunit (struct objfile *objfile, const char *comp_dir, + enum language language) { struct buildsym_compunit *bscu; @@ -777,6 +784,7 @@ start_buildsym_compunit (struct objfile *objfile, const char *comp_dir) bscu->objfile = objfile; bscu->comp_dir = (comp_dir == NULL) ? NULL : xstrdup (comp_dir); + bscu->language = language; /* Initialize the debug format string to NULL. We may supply it later via a call to record_debugformat. */ @@ -1047,11 +1055,11 @@ prepare_for_building (const char *name, CORE_ADDR start_addr) struct compunit_symtab * start_symtab (struct objfile *objfile, const char *name, const char *comp_dir, - CORE_ADDR start_addr) + CORE_ADDR start_addr, enum language language) { prepare_for_building (name, start_addr); - buildsym_compunit = start_buildsym_compunit (objfile, comp_dir); + buildsym_compunit = start_buildsym_compunit (objfile, comp_dir, language); /* Allocate the compunit symtab now. The caller needs it to allocate non-primary symtabs. It is also needed by get_macro_table. */ @@ -1088,7 +1096,8 @@ restart_symtab (struct compunit_symtab *cust, prepare_for_building (name, start_addr); buildsym_compunit = start_buildsym_compunit (COMPUNIT_OBJFILE (cust), - COMPUNIT_DIRNAME (cust)); + COMPUNIT_DIRNAME (cust), + compunit_language (cust)); buildsym_compunit->compunit_symtab = cust; } diff --git a/gdb/buildsym.h b/gdb/buildsym.h index fc5f0e7df61..b72594659bd 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -23,6 +23,7 @@ struct objfile; struct symbol; struct addrmap; struct compunit_symtab; +enum language; /* This module provides definitions used for creating and adding to the symbol table. These routines are called from various symbol- @@ -254,7 +255,8 @@ extern record_line_ftype record_line; extern struct compunit_symtab *start_symtab (struct objfile *objfile, const char *name, const char *comp_dir, - CORE_ADDR start_addr); + CORE_ADDR start_addr, + enum language language); extern void restart_symtab (struct compunit_symtab *cust, const char *name, CORE_ADDR start_addr); diff --git a/gdb/c-lang.c b/gdb/c-lang.c index a1001992fcb..a61540d272f 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -34,6 +34,9 @@ #include "gdb_obstack.h" #include #include "gdbcore.h" +#include "symtab.h" +#include "block.h" +#include "linespec.h" /* for find_toplevel_char */ extern void _initialize_c_language (void); @@ -713,6 +716,67 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp, return evaluate_subexp_standard (expect_type, exp, pos, noside); } +/* Compute the C++ hash for STRING0. + + For dictionaries, we group like-symbols together. + That means that all templates with the same unparameterized names + must yield the same hash. Likewise, overloaded functions must also + yield the same hash. + + The following code deals largely with templates. The dreaded + strcmp_iw already enforces overloads to be grouped. */ + +static unsigned int +cplus_compute_string_hash (const char *string0) +{ + /* If '<' doesn't appear at all in STRING), there is no way we could + be dealing with a template name. */ + if (find_toplevel_char (string0, '<') == NULL) + return default_compute_string_hash (string0); + + /* Locate the last qualified component of STRING0. */ + const char *p = find_toplevel_string (string0, "::"); + const char *last_scope = NULL; + + while (p != NULL) + { + last_scope = p; + p = find_toplevel_string (p + 2, "::"); + } + + /* last_scope points to the last "::". If NULL, then no scope operator + was seen in STRING0, and we use the entire string. */ + if (last_scope == NULL) + last_scope = string0; + + /* Find a possible template parameter list. Valid operators will be + dealt with later. */ + p = find_toplevel_char (last_scope, '<'); + + /* P points to toplevel '<', but it could still be a valid operator + and not be a template at all. */ + if ((p - last_scope) > 8 && strncmp (p - 8, "operator", 8) == 0) + { + /* Skip <,=. */ + while (strchr ("<=", *p) != NULL) + ++p; + + /* Check if this operator contains a template parameter list marker. */ + p = find_toplevel_char (p, '<'); + } + + /* If NULL, the string represents an operator (<, <=, <<, <<=) and is not + a template function itself. */ + if (p == NULL) + return default_compute_string_hash (string0); + + char *copy = ASTRDUP (string0); + + copy[p - string0] = '\0'; + + /* It is a template, compute the hash based only until P. */ + return default_compute_string_hash (copy); +} /* Table mapping opcodes into strings for printing operators @@ -867,6 +931,7 @@ const struct language_defn c_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &c_varobj_ops, c_get_compile_context, c_compute_program, @@ -1001,6 +1066,7 @@ const struct language_defn cplus_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + cplus_compute_string_hash, &cplus_varobj_ops, NULL, NULL, @@ -1053,6 +1119,7 @@ const struct language_defn asm_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, @@ -1105,6 +1172,7 @@ const struct language_defn minimal_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/coffread.c b/gdb/coffread.c index 9db47925573..db0b77a5c60 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -394,7 +394,9 @@ coff_start_symtab (struct objfile *objfile, const char *name) NULL, /* The start address is irrelevant, since we set last_source_start_addr in coff_end_symtab. */ - 0); + 0, + /* Let buildsym.c deduce the language for this symtab. */ + language_unknown); record_debugformat ("COFF"); } diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 91b3cb08bf2..b6f96056738 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -833,6 +833,49 @@ cp_func_name (const char *full_name) return ret; } +/* See description in cp-support.h. */ + +char * +cp_strip_template_parameters (const char *linkage_or_phys_name) +{ + /* We do not turn the linkage name into demangle components since we cannot + walk the tree in any usable way when dealing with conversion operators. + Instead we use a heuristic approach that works for all cases. */ + char *stripped = NULL; + const char *name; + + char *demangled_name = gdb_demangle (linkage_or_phys_name, DMGL_ANSI); + if (demangled_name != NULL) + name = demangled_name; + else + name = linkage_or_phys_name; + + /* Only attempt to strip this if it looks like a template. */ + if (strchr (name, '<') != NULL && strchr (name, '>') != NULL) + { + const char *p; + size_t len = strlen (name) - 1; + + /* This is evil, but since we cannot use demangler trees, we have + no choice but to do textual searches. It is simply easiest to + do this backwards. */ + + /* Since we are searching backwards, we need only find the opening + '<' from the end of the string (at the "top level"). */ + p = find_toplevel_char_r (name, len, '<'); + if (p != NULL) + { + /* Remove any trailing whitespace. */ + while (p > name && (ISSPACE (*(p - 1)))) + --p; + stripped = savestring (name, p - name); + } + } + + xfree (demangled_name); + return stripped; +} + /* DEMANGLED_NAME is the name of a function, including parameters and (optionally) a return type. Return the name of the function without parameters or return type, or NULL if we can not parse the name. */ diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 9054bf678c8..d14e9cc8f8e 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -87,6 +87,11 @@ extern unsigned int cp_entire_prefix_len (const char *name); extern char *cp_func_name (const char *full_name); +/* Strip any template parameters from the template in LINKAGE_NAME. + Result must be free'd. */ + +extern char *cp_strip_template_parameters (const char *linkage_name); + extern char *cp_remove_params (const char *demangled_name); extern struct symbol **make_symbol_overload_list (const char *, diff --git a/gdb/d-lang.c b/gdb/d-lang.c index 3ffdbdf5083..30731b75017 100644 --- a/gdb/d-lang.c +++ b/gdb/d-lang.c @@ -246,6 +246,7 @@ static const struct language_defn d_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/dbxread.c b/gdb/dbxread.c index e95d2287ff5..712f0cdc06a 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -54,7 +54,6 @@ #include "cp-support.h" #include "psympriv.h" #include "block.h" - #include "aout/aout64.h" #include "aout/stab_gnu.h" /* We always use GNU stabs, not native, now. */ @@ -92,6 +91,7 @@ struct symloc int symbol_offset; int string_offset; int file_string_offset; + enum language pst_language; }; #define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff) @@ -101,6 +101,7 @@ struct symloc #define SYMBOL_OFFSET(p) (SYMLOC(p)->symbol_offset) #define STRING_OFFSET(p) (SYMLOC(p)->string_offset) #define FILE_STRING_OFFSET(p) (SYMLOC(p)->file_string_offset) +#define PST_LANGUAGE(p) (SYMLOC(p)->pst_language) /* The objfile we are currently reading. */ @@ -1420,6 +1421,7 @@ read_dbx_symtab (minimal_symbol_reader &reader, struct objfile *objfile) || psymtab_language != language_cplus)) psymtab_language = tmp_language; + /* In C++, one may expect the same filename to come round many times, when code is coming alternately from the main file and from inline functions in other files. So I check to see @@ -2015,6 +2017,7 @@ start_psymtab (struct objfile *objfile, char *filename, CORE_ADDR textlow, /* Deduce the source language from the filename for this psymtab. */ psymtab_language = deduce_language_from_filename (filename); + PST_LANGUAGE (result) = psymtab_language; return result; } @@ -2401,7 +2404,8 @@ read_ofile_symtab (struct objfile *objfile, struct partial_symtab *pst) positive offsets. */ nlist.n_value = (nlist.n_value ^ 0x80000000) - 0x80000000; process_one_symbol (type, nlist.n_desc, nlist.n_value, - namestring, section_offsets, objfile); + namestring, section_offsets, objfile, + PST_LANGUAGE (pst)); } /* We skip checking for a new .o or -l file; that should never happen in this routine. */ @@ -2501,7 +2505,7 @@ cp_set_block_scope (const struct symbol *symbol, void process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, const struct section_offsets *section_offsets, - struct objfile *objfile) + struct objfile *objfile, enum language language) { struct gdbarch *gdbarch = get_objfile_arch (objfile); struct context_stack *newobj; @@ -2715,7 +2719,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, char *name, function_start_offset = 0; start_stabs (); - start_symtab (objfile, name, NULL, valu); + start_symtab (objfile, name, NULL, valu, language); record_debugformat ("stabs"); break; diff --git a/gdb/dictionary.c b/gdb/dictionary.c index e78db2ebe76..fc6498d139d 100644 --- a/gdb/dictionary.c +++ b/gdb/dictionary.c @@ -165,6 +165,7 @@ struct dictionary_linear_expandable struct dictionary { + const struct language_defn *language; const struct dict_vector *vector; union { @@ -179,6 +180,7 @@ struct dictionary /* Accessor macros. */ #define DICT_VECTOR(d) (d)->vector +#define DICT_LANGUAGE(d) (d)->language /* These can be used for DICT_HASHED_EXPANDABLE, too. */ @@ -245,8 +247,6 @@ static struct symbol *iter_match_next_hashed (const char *name, symbol_compare_ftype *compare, struct dict_iterator *iterator); -static unsigned int dict_hash (const char *string); - /* Functions only for DICT_HASHED. */ static int size_hashed (const struct dictionary *dict); @@ -354,6 +354,7 @@ static void expand_hashtable (struct dictionary *dict); struct dictionary * dict_create_hashed (struct obstack *obstack, + enum language language, const struct pending *symbol_list) { struct dictionary *retval; @@ -363,6 +364,7 @@ dict_create_hashed (struct obstack *obstack, retval = XOBNEW (obstack, struct dictionary); DICT_VECTOR (retval) = &dict_hashed_vector; + DICT_LANGUAGE (retval) = language_def (language); /* Calculate the number of symbols, and allocate space for them. */ for (list_counter = symbol_list; @@ -397,11 +399,12 @@ dict_create_hashed (struct obstack *obstack, it. */ extern struct dictionary * -dict_create_hashed_expandable (void) +dict_create_hashed_expandable (enum language language) { struct dictionary *retval = XNEW (struct dictionary); DICT_VECTOR (retval) = &dict_hashed_expandable_vector; + DICT_LANGUAGE (retval) = language_def (language); DICT_HASHED_NBUCKETS (retval) = DICT_EXPANDABLE_INITIAL_CAPACITY; DICT_HASHED_BUCKETS (retval) = XCNEWVEC (struct symbol *, DICT_EXPANDABLE_INITIAL_CAPACITY); @@ -417,6 +420,7 @@ dict_create_hashed_expandable (void) struct dictionary * dict_create_linear (struct obstack *obstack, + enum language language, const struct pending *symbol_list) { struct dictionary *retval; @@ -426,6 +430,7 @@ dict_create_linear (struct obstack *obstack, retval = XOBNEW (obstack, struct dictionary); DICT_VECTOR (retval) = &dict_linear_vector; + DICT_LANGUAGE (retval) = language_def (language); /* Calculate the number of symbols, and allocate space for them. */ for (list_counter = symbol_list; @@ -461,11 +466,12 @@ dict_create_linear (struct obstack *obstack, it. */ struct dictionary * -dict_create_linear_expandable (void) +dict_create_linear_expandable (enum language language) { struct dictionary *retval = XNEW (struct dictionary); DICT_VECTOR (retval) = &dict_linear_expandable_vector; + DICT_LANGUAGE (retval) = language_def (language); DICT_LINEAR_NSYMS (retval) = 0; DICT_LINEAR_EXPANDABLE_CAPACITY (retval) = DICT_EXPANDABLE_INITIAL_CAPACITY; DICT_LINEAR_SYMS (retval) @@ -652,7 +658,8 @@ iter_match_first_hashed (const struct dictionary *dict, const char *name, symbol_compare_ftype *compare, struct dict_iterator *iterator) { - unsigned int hash_index = dict_hash (name) % DICT_HASHED_NBUCKETS (dict); + unsigned int hash_index = (DICT_LANGUAGE (dict)->la_compute_string_hash (name) + % DICT_HASHED_NBUCKETS (dict)); struct symbol *sym; DICT_ITERATOR_DICT (iterator) = dict; @@ -665,12 +672,18 @@ iter_match_first_hashed (const struct dictionary *dict, const char *name, sym != NULL; sym = sym->hash_next) { + //printf ("compare (%s, %s)\n", name, SYMBOL_SEARCH_NAME (sym)); /* Warning: the order of arguments to compare matters! */ if (compare (SYMBOL_SEARCH_NAME (sym), name) == 0) + break; + else if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym)) { - break; + struct template_symbol *tsym = (struct template_symbol *) sym; + + if (tsym->search_name != NULL + && compare (tsym->search_name, name) == 0) + break; } - } DICT_ITERATOR_CURRENT (iterator) = sym; @@ -689,6 +702,14 @@ iter_match_next_hashed (const char *name, symbol_compare_ftype *compare, { if (compare (SYMBOL_SEARCH_NAME (next), name) == 0) break; + else if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (next)) + { + struct template_symbol *tsym = (struct template_symbol *) next; + + if (tsym->search_name != NULL + && compare (tsym->search_name, name) == 0) + break; + } } DICT_ITERATOR_CURRENT (iterator) = next; @@ -705,8 +726,13 @@ insert_symbol_hashed (struct dictionary *dict, unsigned int hash_index; struct symbol **buckets = DICT_HASHED_BUCKETS (dict); - hash_index = - dict_hash (SYMBOL_SEARCH_NAME (sym)) % DICT_HASHED_NBUCKETS (dict); + /* We don't want to insert a symbol into a dictionary of a different + language. The two may not use the same hashing algorithm. */ + gdb_assert (SYMBOL_LANGUAGE (sym) == DICT_LANGUAGE (dict)->la_language); + + hash_index + = (DICT_LANGUAGE (dict)->la_compute_string_hash (SYMBOL_SEARCH_NAME (sym)) + % DICT_HASHED_NBUCKETS (dict)); sym->hash_next = buckets[hash_index]; buckets[hash_index] = sym; } @@ -784,7 +810,7 @@ expand_hashtable (struct dictionary *dict) That is, two identifiers equivalent according to any of those three comparison operators hash to the same value. */ -static unsigned int +unsigned int dict_hash (const char *string0) { /* The Ada-encoded version of a name P1.P2...Pn has either the form @@ -903,6 +929,17 @@ iter_match_next_linear (const char *name, symbol_compare_ftype *compare, retval = sym; break; } + else if (SYMBOL_IS_CPLUS_TEMPLATE_FUNCTION (sym)) + { + struct template_symbol *tsym = (struct template_symbol *) sym; + + if (tsym->search_name != NULL + && compare (tsym->search_name, name) == 0) + { + retval = sym; + break; + } + } } DICT_ITERATOR_INDEX (iterator) = i; diff --git a/gdb/dictionary.h b/gdb/dictionary.h index 124fc983801..cf0dc5decf5 100644 --- a/gdb/dictionary.h +++ b/gdb/dictionary.h @@ -35,7 +35,7 @@ struct dictionary; struct symbol; struct obstack; struct pending; - +struct language_defn; /* The creation functions for various implementations of dictionaries. */ @@ -45,6 +45,7 @@ struct pending; initialized from SYMBOL_LIST. */ extern struct dictionary *dict_create_hashed (struct obstack *obstack, + enum language language, const struct pending *symbol_list); @@ -53,7 +54,8 @@ extern struct dictionary *dict_create_hashed (struct obstack *obstack, it, call dict_add_symbol(). Call dict_free() when you're done with it. */ -extern struct dictionary *dict_create_hashed_expandable (void); +extern struct dictionary * + dict_create_hashed_expandable (enum language language); /* Create a dictionary implemented via a fixed-size array. All memory it uses is allocated on OBSTACK; the environment is initialized @@ -61,6 +63,7 @@ extern struct dictionary *dict_create_hashed_expandable (void); that they're found in SYMBOL_LIST. */ extern struct dictionary *dict_create_linear (struct obstack *obstack, + enum language language, const struct pending *symbol_list); @@ -69,8 +72,12 @@ extern struct dictionary *dict_create_linear (struct obstack *obstack, it, call dict_add_symbol(). Call dict_free() when you're done with it. */ -extern struct dictionary *dict_create_linear_expandable (void); +extern struct dictionary * + dict_create_linear_expandable (enum language language); + +/* A default hashing function for symbols. */ +extern unsigned int dict_hash (const char *string0); /* The functions providing the interface to dictionaries. Note that the most common parts of the interface, namely symbol lookup, are diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index d09aa417dba..2e2c58d0dbf 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -11596,6 +11596,24 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) VEC_address (symbolp, template_args), (templ_func->n_template_arguments * sizeof (struct symbol *))); VEC_free (symbolp, template_args); + const char *linkage_name = dw2_linkage_name (die, cu); + if (linkage_name != NULL) + { + char *str; + + str = cp_strip_template_parameters (linkage_name); + if (str != NULL) + { + /* It would be nice to assert on the return value. Alas, + the demangler could be old/outdated and unable to demangle + the given linkage name. We have to cope with that + gracefully, even though a small part of me dies every time + this happens. */ + templ_func->search_name + = obstack_strdup (&objfile->objfile_obstack, str); + xfree (str); + } + } } /* In C++, we can have functions nested inside functions (e.g., when @@ -18839,7 +18857,7 @@ dwarf2_start_symtab (struct dwarf2_cu *cu, const char *name, const char *comp_dir, CORE_ADDR low_pc) { struct compunit_symtab *cust - = start_symtab (cu->objfile, name, comp_dir, low_pc); + = start_symtab (cu->objfile, name, comp_dir, low_pc, cu->language); record_debugformat ("DWARF 2"); record_producer (cu->producer); diff --git a/gdb/f-lang.c b/gdb/f-lang.c index 8aba5efe027..c1c1291c21f 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -289,6 +289,7 @@ const struct language_defn f_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/go-lang.c b/gdb/go-lang.c index 88ddfb66be7..03aba11bdee 100644 --- a/gdb/go-lang.c +++ b/gdb/go-lang.c @@ -607,6 +607,7 @@ static const struct language_defn go_language_defn = c_get_string, NULL, iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/jit.c b/gdb/jit.c index 158d6d82154..b2ef66d29ef 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -657,12 +657,14 @@ finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile) size_t blockvector_size; CORE_ADDR begin, end; struct blockvector *bv; + enum language language; actual_nblocks = FIRST_LOCAL_BLOCK + stab->nblocks; cust = allocate_compunit_symtab (objfile, stab->file_name); allocate_symtab (cust, stab->file_name); add_compunit_symtab_to_objfile (cust); + language = compunit_language (cust); /* JIT compilers compile in memory. */ COMPUNIT_DIRNAME (cust) = NULL; @@ -707,7 +709,7 @@ finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile) "void"); BLOCK_DICT (new_block) = dict_create_linear (&objfile->objfile_obstack, - NULL); + language, NULL); /* The address range. */ BLOCK_START (new_block) = (CORE_ADDR) gdb_block_iter->begin; BLOCK_END (new_block) = (CORE_ADDR) gdb_block_iter->end; @@ -745,7 +747,7 @@ finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile) ? allocate_global_block (&objfile->objfile_obstack) : allocate_block (&objfile->objfile_obstack)); BLOCK_DICT (new_block) = dict_create_linear (&objfile->objfile_obstack, - NULL); + language, NULL); BLOCK_SUPERBLOCK (new_block) = block_iter; block_iter = new_block; diff --git a/gdb/language.c b/gdb/language.c index 31c5c591ab7..b1c79e963c2 100644 --- a/gdb/language.c +++ b/gdb/language.c @@ -43,6 +43,7 @@ #include "symfile.h" #include "cp-support.h" #include "frame.h" +#include "dictionary.h" /* for dict_hash */ extern void _initialize_language (void); @@ -723,6 +724,14 @@ default_get_string (struct value *value, gdb_byte **buffer, int *length, error (_("Getting a string is unsupported in this language.")); } +/* See language.h. */ + +unsigned int +default_compute_string_hash (const char *name) +{ + return dict_hash (name); +} + /* Define the language that is no language. */ static int @@ -862,6 +871,7 @@ const struct language_defn unknown_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, @@ -911,6 +921,7 @@ const struct language_defn auto_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, @@ -958,6 +969,7 @@ const struct language_defn local_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/language.h b/gdb/language.h index b808c9e91af..2bf677c43e7 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -385,6 +385,10 @@ struct language_defn symbol_found_callback_ftype *callback, void *data); + /* Hash the given STRING. Use default_compute_string_hash if no + special treatment is required. */ + unsigned int (*la_compute_string_hash) (const char *name); + /* Various operations on varobj. */ const struct lang_varobj_ops *la_varobj_ops; @@ -609,6 +613,10 @@ void default_print_typedef (struct type *type, struct symbol *new_symbol, void default_get_string (struct value *value, gdb_byte **buffer, int *length, struct type **char_type, const char **charset); +/* Default name hashing function. */ + +extern unsigned int default_compute_string_hash (const char *string); + void c_get_string (struct value *value, gdb_byte **buffer, int *length, struct type **char_type, const char **charset); diff --git a/gdb/linespec.c b/gdb/linespec.c index 9d0dab062d7..dddcbac3202 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -1138,72 +1138,6 @@ find_methods (struct type *t, const char *name, VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase)); } -/* Find an instance of the character C in the string S that is outside - of all parenthesis pairs, single-quoted strings, and double-quoted - strings. Also, ignore the char within a template name, like a ',' - within foo. */ - -const char * -find_toplevel_char (const char *s, char c) -{ - int quoted = 0; /* zero if we're not in quotes; - '"' if we're in a double-quoted string; - '\'' if we're in a single-quoted string. */ - int depth = 0; /* Number of unclosed parens we've seen. */ - const char *scan; - - for (scan = s; *scan; scan++) - { - if (quoted) - { - if (*scan == quoted) - quoted = 0; - else if (*scan == '\\' && *(scan + 1)) - scan++; - } - else if (*scan == c && ! quoted && depth == 0) - return scan; - else if (*scan == '"' || *scan == '\'') - quoted = *scan; - else if (*scan == '(' || *scan == '<') - depth++; - else if ((*scan == ')' || *scan == '>') && depth > 0) - depth--; - } - - return 0; -} - -/* The string equivalent of find_toplevel_char. Returns a pointer - to the location of NEEDLE in HAYSTACK, ignoring any occurrences - inside "()" and "<>". Returns NULL if NEEDLE was not found. */ - -static const char * -find_toplevel_string (const char *haystack, const char *needle) -{ - const char *s = haystack; - - do - { - s = find_toplevel_char (s, *needle); - - if (s != NULL) - { - /* Found first char in HAYSTACK; check rest of string. */ - if (startswith (s, needle)) - return s; - - /* Didn't find it; loop over HAYSTACK, looking for the next - instance of the first character of NEEDLE. */ - ++s; - } - } - while (s != NULL && *s != '\0'); - - /* NEEDLE was not found in HAYSTACK. */ - return NULL; -} - /* Convert CANONICAL to its string representation using symtab_to_fullname for SYMTAB. The caller must xfree the result. */ diff --git a/gdb/linespec.h b/gdb/linespec.h index 4e698958a43..f4923a752e3 100644 --- a/gdb/linespec.h +++ b/gdb/linespec.h @@ -175,13 +175,6 @@ extern const char *get_gdb_linespec_parser_quote_characters (void); extern int is_ada_operator (const char *string); -/* Find an instance of the character C in the string S that is outside - of all parenthesis pairs, single-quoted strings, and double-quoted - strings. Also, ignore the char within a template name, like a ',' - within foo. */ - -extern const char *find_toplevel_char (const char *s, char c); - /* Find the end of the (first) linespec pointed to by *STRINGP. STRINGP will be advanced to this point. */ diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 03b955cb63a..684393f24e4 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -395,6 +395,7 @@ const struct language_defn m2_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c index 952dffb60a3..3ab28154da7 100644 --- a/gdb/mdebugread.c +++ b/gdb/mdebugread.c @@ -236,7 +236,7 @@ static struct type *new_type (char *); enum block_type { FUNCTION_BLOCK, NON_FUNCTION_BLOCK }; -static struct block *new_block (enum block_type); +static struct block *new_block (enum block_type, enum language); static struct compunit_symtab *new_symtab (const char *, int, struct objfile *); @@ -811,7 +811,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend, TYPE_PROTOTYPED (SYMBOL_TYPE (s)) = 1; /* Create and enter a new lexical context. */ - b = new_block (FUNCTION_BLOCK); + b = new_block (FUNCTION_BLOCK, SYMBOL_LANGUAGE (s)); SYMBOL_BLOCK_VALUE (s) = b; BLOCK_FUNCTION (b) = s; BLOCK_START (b) = BLOCK_END (b) = sh->value; @@ -1144,7 +1144,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend, } top_stack->blocktype = stBlock; - b = new_block (NON_FUNCTION_BLOCK); + b = new_block (NON_FUNCTION_BLOCK, SYMBOL_LANGUAGE (s)); BLOCK_START (b) = sh->value + top_stack->procadr; BLOCK_SUPERBLOCK (b) = top_stack->cur_block; top_stack->cur_block = b; @@ -4026,6 +4026,7 @@ psymtab_to_symtab_1 (struct objfile *objfile, if (ECOFF_IS_STAB (&sh) || (name[0] == '#')) { int type_code = ECOFF_UNMARK_STAB (sh.index); + enum language language = PST_PRIVATE (pst)->pst_language; /* We should never get non N_STAB symbols here, but they should be harmless, so keep process_one_symbol from @@ -4053,14 +4054,14 @@ psymtab_to_symtab_1 (struct objfile *objfile, { last_symtab_ended = 0; process_one_symbol (type_code, 0, valu, name, - section_offsets, objfile); + section_offsets, objfile, language); } } /* Similarly a hack. */ else if (name[0] == '#') { process_one_symbol (N_SLINE, 0, valu, name, - section_offsets, objfile); + section_offsets, objfile, language); } if (type_code == N_FUN) { @@ -4721,16 +4722,18 @@ new_symtab (const char *name, int maxlines, struct objfile *objfile) struct compunit_symtab *cust = allocate_compunit_symtab (objfile, name); struct symtab *symtab; struct blockvector *bv; + enum language lang; add_compunit_symtab_to_objfile (cust); symtab = allocate_symtab (cust, name); SYMTAB_LINETABLE (symtab) = new_linetable (maxlines); + lang = compunit_language (cust); /* All symtabs must have at least two blocks. */ bv = new_bvect (2); - BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = new_block (NON_FUNCTION_BLOCK); - BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = new_block (NON_FUNCTION_BLOCK); + BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = new_block (NON_FUNCTION_BLOCK, lang); + BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = new_block (NON_FUNCTION_BLOCK, lang); BLOCK_SUPERBLOCK (BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK)) = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); COMPUNIT_BLOCKVECTOR (cust) = bv; @@ -4818,7 +4821,7 @@ new_bvect (int nblocks) hashed. */ static struct block * -new_block (enum block_type type) +new_block (enum block_type type, enum language language) { /* FIXME: carlton/2003-09-11: This should use allocate_block to allocate the block. Which, in turn, suggests that the block @@ -4826,9 +4829,9 @@ new_block (enum block_type type) struct block *retval = XCNEW (struct block); if (type == FUNCTION_BLOCK) - BLOCK_DICT (retval) = dict_create_linear_expandable (); + BLOCK_DICT (retval) = dict_create_linear_expandable (language); else - BLOCK_DICT (retval) = dict_create_hashed_expandable (); + BLOCK_DICT (retval) = dict_create_hashed_expandable (language); return retval; } diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c index ad7c64ea9fe..200beeaa5f4 100644 --- a/gdb/objc-lang.c +++ b/gdb/objc-lang.c @@ -404,6 +404,7 @@ const struct language_defn objc_language_defn = { default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c index 6e4c185a646..bd2c8380115 100644 --- a/gdb/opencl-lang.c +++ b/gdb/opencl-lang.c @@ -1084,6 +1084,7 @@ const struct language_defn opencl_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/p-lang.c b/gdb/p-lang.c index 1b069ef17fe..89ba27d7cb9 100644 --- a/gdb/p-lang.c +++ b/gdb/p-lang.c @@ -457,6 +457,7 @@ const struct language_defn pascal_language_defn = default_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c index 4977b0a1aa3..10091d4001e 100644 --- a/gdb/rust-lang.c +++ b/gdb/rust-lang.c @@ -2178,6 +2178,7 @@ static const struct language_defn rust_language_defn = c_get_string, NULL, /* la_get_symbol_name_cmp */ iterate_over_symbols, + default_compute_string_hash, &default_varobj_ops, NULL, NULL, diff --git a/gdb/stabsread.h b/gdb/stabsread.h index 988063f2429..d537e49c804 100644 --- a/gdb/stabsread.h +++ b/gdb/stabsread.h @@ -17,6 +17,7 @@ along with this program. If not, see . */ struct objfile; +enum language; /* Definitions, prototypes, etc for stabs debugging format support functions. @@ -169,7 +170,7 @@ extern struct partial_symtab *dbx_end_psymtab extern void process_one_symbol (int, int, CORE_ADDR, char *, const struct section_offsets *, - struct objfile *); + struct objfile *, enum language); extern void elfstab_build_psymtabs (struct objfile *objfile, asection *stabsect, diff --git a/gdb/symtab.h b/gdb/symtab.h index 6cae5717005..df4ef856a7d 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -904,6 +904,9 @@ struct template_symbol /* The base class. */ struct symbol base; + /* Search name of the template (it's name sans parameters). */ + char *search_name; + /* The number of template arguments. */ int n_template_arguments; diff --git a/gdb/testsuite/gdb.cp/mb-templates.cc b/gdb/testsuite/gdb.cp/mb-templates.cc index 649d7eda69f..46c189c0920 100644 --- a/gdb/testsuite/gdb.cp/mb-templates.cc +++ b/gdb/testsuite/gdb.cp/mb-templates.cc @@ -8,6 +8,45 @@ void foo(T i) std::cout << "hi\n"; // set breakpoint here } +template +T bar (void) +{ + return -100; +} + +template +T bar(T i) +{ + return i; +} + +template +T bar(T i, T j) +{ + return i - j; +} + +namespace N +{ + template + T bar (void) + { + return static_cast (V); + } + + template + T bar (T i) + { + return i - static_cast (V); + } + + template + T bar (T i, T j) + { + return 100; + } +}; + template void multi_line_foo(T i) { @@ -27,5 +66,9 @@ int main() multi_line_foo(0); multi_line_foo(0); - return 0; + using namespace N; + return bar () + bar (1) + bar (2, 3) + + bar (1) + bar (2, 3) + + bar () + bar (0) + bar (1, 2) + + bar (); } diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp index d2baed06bc1..1d53c6717fb 100644 --- a/gdb/testsuite/gdb.cp/mb-templates.exp +++ b/gdb/testsuite/gdb.cp/mb-templates.exp @@ -49,7 +49,6 @@ set test "initial condition: run to breakpoint" gdb_test_multiple "" $test { -re "Breakpoint \[0-9\]+,.*foo \\(i=1\\).*$gdb_prompt $" { pass $test - break } } @@ -130,3 +129,18 @@ gdb_test "continue" \ gdb_test "continue" \ ".*Breakpoint.*multi_line_foo \\(i=0\\).*" \ "run to multi_line_foo breakpoint 2 " + +# Test setting breakpoints on template "base" names. + +# gdb_breakpoint is avoid in several test because we want to test +# that multiple locations were set for each breakpoint. + +gdb_test "break bar" [string_to_regexp "(5 locations)"] +gdb_test "break bar" [string_to_regexp "(3 locations)"] +gdb_test "break bar" [string_to_regexp "(2 locations)"] +gdb_breakpoint "bar(void)" message +gdb_breakpoint "bar(char)" message +gdb_test "break N::bar" [string_to_regexp "(4 locations)"] +gdb_test "break N::bar" [string_to_regexp "(3 locations)"] +gdb_breakpoint "N::bar(void)" message +gdb_breakpoint "N::bar (void)" message diff --git a/gdb/utils.c b/gdb/utils.c index 27021a1d458..db00744fbde 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -3395,6 +3395,98 @@ strip_leading_path_elements (const char *path, int n) return p; } +/* See description in utils.h. */ + +const char * +find_toplevel_char (const char *s, char c) +{ + int quoted = 0; /* zero if we're not in quotes; + '"' if we're in a double-quoted string; + '\'' if we're in a single-quoted string. */ + int depth = 0; /* Number of unclosed parens we've seen. */ + const char *scan; + + for (scan = s; *scan; scan++) + { + if (quoted) + { + if (*scan == quoted) + quoted = 0; + else if (*scan == '\\' && *(scan + 1)) + scan++; + } + else if (*scan == c && ! quoted && depth == 0) + return scan; + else if (*scan == '"' || *scan == '\'') + quoted = *scan; + else if (*scan == '(' || *scan == '<') + depth++; + else if ((*scan == ')' || *scan == '>') && depth > 0) + depth--; + } + + return 0; +} + +/* See description in utils.h. */ + +const char * +find_toplevel_char_r (const char *s, size_t len, char c) +{ + int quoted = 0; + int depth = 0; + const char *scan; + + for (scan = s + len; scan >= s; --scan) + { + if (quoted) + { + if (*scan == quoted) + quoted = 0; + } + else if (*scan == ')' || *scan == '>') + ++depth; + else if ((*scan == '(' || *scan == '<') && depth > 0) + --depth; + + if (*scan == c && !quoted && depth == 0) + return scan; + else if ((*scan == '"' || *scan == '\'') + && scan > s && *(scan - 1) != '\\') + quoted = *scan; + } + + return NULL; +} + +/* See description in utils.h. */ + +const char * +find_toplevel_string (const char *haystack, const char *needle) +{ + const char *s = haystack; + + do + { + s = find_toplevel_char (s, *needle); + + if (s != NULL) + { + /* Found first char in HAYSTACK; check rest of string. */ + if (startswith (s, needle)) + return s; + + /* Didn't find it; loop over HAYSTACK, looking for the next + instance of the first character of NEEDLE. */ + ++s; + } + } + while (s != NULL && *s != '\0'); + + /* NEEDLE was not found in HAYSTACK. */ + return NULL; +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_utils; diff --git a/gdb/utils.h b/gdb/utils.h index f138702b3a4..a9aa9c93a55 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -387,4 +387,22 @@ extern void dump_core (void); extern char *make_hex_string (const gdb_byte *data, size_t length); +/* Find an instance of the character C in the string S that is outside + of all parenthesis pairs, single-quoted strings, and double-quoted + strings. Also, ignore the char within a template name, like a ',' + within foo. */ + +extern const char *find_toplevel_char (const char *s, char c); + +/* Like find_toplevel_char but searches S backwards, starting LEN characters + into S. */ + +extern const char *find_toplevel_char_r (const char *s, size_t len, char c); + +/* The string equivalent of find_toplevel_char. Returns a pointer + to the location of NEEDLE in HAYSTACK, ignoring any occurrences + inside "()" and "<>". Returns NULL if NEEDLE was not found. */ + +const char *find_toplevel_string (const char *haystack, const char *needle); + #endif /* UTILS_H */ diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index 9c4769a7443..4ea25002312 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -1044,7 +1044,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst) last_csect_name = 0; start_stabs (); - start_symtab (objfile, filestring, (char *) NULL, file_start_addr); + start_symtab (objfile, filestring, (char *) NULL, file_start_addr, + language_unknown); record_debugformat (debugfmt); symnum = ((struct symloc *) pst->read_symtab_private)->first_symnum; max_symnum = @@ -1137,7 +1138,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst) } start_stabs (); - start_symtab (objfile, "_globals_", (char *) NULL, (CORE_ADDR) 0); + start_symtab (objfile, "_globals_", (char *) NULL, (CORE_ADDR) 0, + language_unknown); record_debugformat (debugfmt); cur_src_end_addr = first_object_file_end; /* Done with all files, everything from here on is globals. */ @@ -1195,7 +1197,7 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst) /* Give all csects for this source file the same name. */ start_symtab (objfile, filestring, NULL, - (CORE_ADDR) 0); + (CORE_ADDR) 0, language_unknown); record_debugformat (debugfmt); } @@ -1330,7 +1332,8 @@ read_xcoff_symtab (struct objfile *objfile, struct partial_symtab *pst) filestring = cs->c_name; start_stabs (); - start_symtab (objfile, filestring, (char *) NULL, (CORE_ADDR) 0); + start_symtab (objfile, filestring, (char *) NULL, (CORE_ADDR) 0, + language_unknown); record_debugformat (debugfmt); last_csect_name = 0;