X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Flinespec.c;h=a081a8bebfd213a4a21b0c572dce69efab8daff0;hb=6a307fc5f59179005e070bd5a5a4cf78a9ecefd4;hp=7a595ed575dcd2941a297a04c7da5ef20e698399;hpb=acaa662f29836ce4d4c3a0abc2132f285f9df585;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/linespec.c b/gdb/linespec.c index 7a595ed575..a081a8bebf 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -1,6 +1,6 @@ /* Parser for linespec for the GNU debugger, GDB. - Copyright (C) 1986-2015 Free Software Foundation, Inc. + Copyright (C) 1986-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -44,6 +44,38 @@ #include "ada-lang.h" #include "stack.h" #include "location.h" +#include "common/function-view.h" +#include "common/def-vector.h" +#include + +/* An enumeration of the various things a user might attempt to + complete for a linespec location. */ + +enum class linespec_complete_what +{ + /* Nothing, no possible completion. */ + NOTHING, + + /* A function/method name. Due to ambiguity between + + (gdb) b source[TAB] + source_file.c + source_function + + this can also indicate a source filename, iff we haven't seen a + separate source filename component, as in "b source.c:function". */ + FUNCTION, + + /* A label symbol. E.g., break file.c:function:LABEL. */ + LABEL, + + /* An expression. E.g., "break foo if EXPR", or "break *EXPR". */ + EXPRESSION, + + /* A linespec keyword ("if"/"thread"/"task"). + E.g., "break func threa". */ + KEYWORD, +}; typedef struct symbol *symbolp; DEF_VEC_P (symbolp); @@ -123,6 +155,10 @@ struct linespec_state /* The program space as seen when the module was entered. */ struct program_space *program_space; + /* If not NULL, the search is restricted to just this program + space. */ + struct program_space *search_pspace; + /* The default symtab to use, if no other symtab is specified. */ struct symtab *default_symtab; @@ -139,7 +175,7 @@ struct linespec_state /* The 'canonical' value passed to decode_line_full, or NULL. */ struct linespec_result *canonical; - /* Canonical strings that mirror the symtabs_and_lines result. */ + /* Canonical strings that mirror the std::vector result. */ struct linespec_canonical_name *canonical_names; /* This is a set of address_entry objects which is used to prevent @@ -167,8 +203,23 @@ struct collect_info VEC (symbolp) *symbols; VEC (bound_minimal_symbol_d) *minimal_symbols; } result; + + /* Possibly add a symbol to the results. */ + bool add_symbol (symbol *sym); }; +bool +collect_info::add_symbol (symbol *sym) +{ + /* In list mode, add all matching symbols, regardless of class. + This allows the user to type "list a_global_variable". */ + if (SYMBOL_CLASS (sym) == LOC_BLOCK || this->state->list_mode) + VEC_safe_push (symbolp, this->result.symbols, sym); + + /* Continue iterating. */ + return true; +} + /* Token types */ enum ls_token_type @@ -196,9 +247,9 @@ enum ls_token_type }; typedef enum ls_token_type linespec_token_type; -/* List of keywords */ - -static const char * const linespec_keywords[] = { "if", "thread", "task" }; +/* List of keywords. This is NULL-terminated so that it can be used + as enum completer. */ +const char * const linespec_keywords[] = { "if", "thread", "task", NULL }; #define IF_KEYWORD_INDEX 0 /* A token of the linespec lexer */ @@ -251,6 +302,29 @@ struct ls_parser /* The result of the parse. */ struct linespec result; #define PARSER_RESULT(PPTR) (&(PPTR)->result) + + /* What the parser believes the current word point should complete + to. */ + linespec_complete_what complete_what; + + /* The completion word point. The parser advances this as it skips + tokens. At some point the input string will end or parsing will + fail, and then we attempt completion at the captured completion + word point, interpreting the string at completion_word as + COMPLETE_WHAT. */ + const char *completion_word; + + /* If the current token was a quoted string, then this is the + quoting character (either " or '). */ + int completion_quote_char; + + /* If the current token was a quoted string, then this points at the + end of the quoted string. */ + const char *completion_quote_end; + + /* If parsing for completion, then this points at the completion + tracker. Otherwise, this is NULL. */ + struct completion_tracker *completion_tracker; }; typedef struct ls_parser linespec_parser; @@ -260,30 +334,33 @@ typedef struct ls_parser linespec_parser; /* Prototypes for local functions. */ -static void iterate_over_file_blocks (struct symtab *symtab, - const char *name, domain_enum domain, - symbol_found_callback_ftype *callback, - void *data); +static void iterate_over_file_blocks + (struct symtab *symtab, const lookup_name_info &name, + domain_enum domain, + gdb::function_view callback); static void initialize_defaults (struct symtab **default_symtab, int *default_line); CORE_ADDR linespec_expression_to_pc (const char **exp_ptr); -static struct symtabs_and_lines decode_objc (struct linespec_state *self, - linespec_p ls, - const char *arg); +static std::vector decode_objc (struct linespec_state *self, + linespec_p ls, + const char *arg); -static VEC (symtab_ptr) *symtabs_from_filename (const char *); +static VEC (symtab_ptr) *symtabs_from_filename (const char *, + struct program_space *pspace); static VEC (symbolp) *find_label_symbols (struct linespec_state *self, VEC (symbolp) *function_symbols, VEC (symbolp) **label_funcs_ret, - const char *name); + const char *name, + bool completion_mode = false); static void find_linespec_symbols (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, const char *name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms); @@ -295,29 +372,34 @@ static int symbol_to_sal (struct symtab_and_line *result, int funfirstline, struct symbol *sym); static void add_matching_symbols_to_info (const char *name, + symbol_name_match_type name_match_type, + enum search_domain search_domain, struct collect_info *info, struct program_space *pspace); static void add_all_symbol_names_from_pspace (struct collect_info *info, struct program_space *pspace, - VEC (const_char_ptr) *names); + VEC (const_char_ptr) *names, + enum search_domain search_domain); -static VEC (symtab_ptr) *collect_symtabs_from_filename (const char *file); +static VEC (symtab_ptr) * + collect_symtabs_from_filename (const char *file, + struct program_space *pspace); -static void decode_digits_ordinary (struct linespec_state *self, - linespec_p ls, - int line, - struct symtabs_and_lines *sals, - struct linetable_entry **best_entry); +static std::vector decode_digits_ordinary + (struct linespec_state *self, + linespec_p ls, + int line, + linetable_entry **best_entry); -static void decode_digits_list_mode (struct linespec_state *self, - linespec_p ls, - struct symtabs_and_lines *values, - struct symtab_and_line val); +static std::vector decode_digits_list_mode + (struct linespec_state *self, + linespec_p ls, + struct symtab_and_line val); static void minsym_found (struct linespec_state *self, struct objfile *objfile, struct minimal_symbol *msymbol, - struct symtabs_and_lines *result); + std::vector *result); static int compare_symbols (const void *a, const void *b); @@ -378,7 +460,7 @@ linespec_lexer_lex_keyword (const char *p) if (p != NULL) { - for (i = 0; i < ARRAY_SIZE (linespec_keywords); ++i) + for (i = 0; linespec_keywords[i] != NULL; ++i) { int len = strlen (linespec_keywords[i]); @@ -398,8 +480,8 @@ linespec_lexer_lex_keyword (const char *p) if (i != IF_KEYWORD_INDEX) { p += len; - p = skip_spaces_const (p); - for (j = 0; j < ARRAY_SIZE (linespec_keywords); ++j) + p = skip_spaces (p); + for (j = 0; linespec_keywords[j] != NULL; ++j) { int nextlen = strlen (linespec_keywords[j]); @@ -520,6 +602,30 @@ find_parameter_list_end (const char *input) return p; } +/* If the [STRING, STRING_LEN) string ends with what looks like a + keyword, return the keyword start offset in STRING. Return -1 + otherwise. */ + +static size_t +string_find_incomplete_keyword_at_end (const char * const *keywords, + const char *string, size_t string_len) +{ + const char *end = string + string_len; + const char *p = end; + + while (p > string && *p != ' ') + --p; + if (p > string) + { + p++; + size_t len = end - p; + for (size_t i = 0; keywords[i] != NULL; ++i) + if (strncmp (keywords[i], p, len) == 0) + return p - string; + } + + return -1; +} /* Lex a string from the input in PARSER. */ @@ -567,13 +673,31 @@ linespec_lexer_lex_string (linespec_parser *parser) /* Skip to the ending quote. */ end = skip_quote_char (PARSER_STREAM (parser), quote_char); - /* Error if the input did not terminate properly. */ - if (end == NULL) - error (_("unmatched quote")); + /* This helps the completer mode decide whether we have a + complete string. */ + parser->completion_quote_char = quote_char; + parser->completion_quote_end = end; - /* Skip over the ending quote and mark the length of the string. */ - PARSER_STREAM (parser) = (char *) ++end; - LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 2 - start; + /* Error if the input did not terminate properly, unless in + completion mode. */ + if (end == NULL) + { + if (parser->completion_tracker == NULL) + error (_("unmatched quote")); + + /* In completion mode, we'll try to complete the incomplete + token. */ + token.type = LSTOKEN_STRING; + while (*PARSER_STREAM (parser) != '\0') + PARSER_STREAM (parser)++; + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 1 - start; + } + else + { + /* Skip over the ending quote and mark the length of the string. */ + PARSER_STREAM (parser) = (char *) ++end; + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 2 - start; + } } else { @@ -591,7 +715,7 @@ linespec_lexer_lex_string (linespec_parser *parser) { if (isspace (*PARSER_STREAM (parser))) { - p = skip_spaces_const (PARSER_STREAM (parser)); + p = skip_spaces (PARSER_STREAM (parser)); /* When we get here we know we've found something followed by a space (we skip over parens and templates below). So if we find a keyword now, we know it is a keyword and not, @@ -622,6 +746,11 @@ linespec_lexer_lex_string (linespec_parser *parser) if (PARSER_STREAM (parser)[1] == ':') ++(PARSER_STREAM (parser)); + /* Do not tokenize ABI tags such as "[abi:cxx11]". */ + else if (PARSER_STREAM (parser) - start > 4 + && startswith (PARSER_STREAM (parser) - 4, "[abi")) + ++(PARSER_STREAM (parser)); + /* Do not tokenify if the input length so far is one (i.e, a single-letter drive name) and the next character is a directory separator. This allows Windows-style @@ -651,14 +780,50 @@ linespec_lexer_lex_string (linespec_parser *parser) else if (*PARSER_STREAM (parser) == '<' || *PARSER_STREAM (parser) == '(') { - const char *p; + /* Don't interpret 'operator<' / 'operator<<' as a + template parameter list though. */ + if (*PARSER_STREAM (parser) == '<' + && (PARSER_STATE (parser)->language->la_language + == language_cplus) + && (PARSER_STREAM (parser) - start) >= CP_OPERATOR_LEN) + { + const char *p = PARSER_STREAM (parser); + + while (p > start && isspace (p[-1])) + p--; + if (p - start >= CP_OPERATOR_LEN) + { + p -= CP_OPERATOR_LEN; + if (strncmp (p, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0 + && (p == start + || !(isalnum (p[-1]) || p[-1] == '_'))) + { + /* This is an operator name. Keep going. */ + ++(PARSER_STREAM (parser)); + if (*PARSER_STREAM (parser) == '<') + ++(PARSER_STREAM (parser)); + continue; + } + } + } + + const char *p = find_parameter_list_end (PARSER_STREAM (parser)); + PARSER_STREAM (parser) = p; - p = find_parameter_list_end (PARSER_STREAM (parser)); - if (p != NULL) + /* Don't loop around to the normal \0 case above because + we don't want to misinterpret a potential keyword at + the end of the token when the string isn't + "()<>"-balanced. This handles "b + function(thread" in completion mode. */ + if (*p == '\0') { - PARSER_STREAM (parser) = p; - continue; + LS_TOKEN_STOKEN (token).ptr = start; + LS_TOKEN_STOKEN (token).length + = PARSER_STREAM (parser) - start; + return token; } + else + continue; } /* Commas are terminators, but not if they are part of an operator name. */ @@ -666,10 +831,9 @@ linespec_lexer_lex_string (linespec_parser *parser) { if ((PARSER_STATE (parser)->language->la_language == language_cplus) - && (PARSER_STREAM (parser) - start) > 8 - /* strlen ("operator") */) + && (PARSER_STREAM (parser) - start) > CP_OPERATOR_LEN) { - const char *p = strstr (start, "operator"); + const char *p = strstr (start, CP_OPERATOR_STR); if (p != NULL && is_operator_name (p)) { @@ -703,7 +867,7 @@ linespec_lexer_lex_one (linespec_parser *parser) if (parser->lexer.current.type == LSTOKEN_CONSUMED) { /* Skip any whitespace. */ - PARSER_STREAM (parser) = skip_spaces_const (PARSER_STREAM (parser)); + PARSER_STREAM (parser) = skip_spaces (PARSER_STREAM (parser)); /* Check for a keyword, they end the linespec. */ keyword = linespec_lexer_lex_keyword (PARSER_STREAM (parser)); @@ -777,13 +941,48 @@ linespec_lexer_lex_one (linespec_parser *parser) } /* Consume the current token and return the next token in PARSER's - input stream. */ + input stream. Also advance the completion word for completion + mode. */ static linespec_token linespec_lexer_consume_token (linespec_parser *parser) { + gdb_assert (parser->lexer.current.type != LSTOKEN_EOI); + + bool advance_word = (parser->lexer.current.type != LSTOKEN_STRING + || *PARSER_STREAM (parser) != '\0'); + + /* If we're moving past a string to some other token, it must be the + quote was terminated. */ + if (parser->completion_quote_char) + { + gdb_assert (parser->lexer.current.type == LSTOKEN_STRING); + + /* If the string was the last (non-EOI) token, we're past the + quote, but remember that for later. */ + if (*PARSER_STREAM (parser) != '\0') + { + parser->completion_quote_char = '\0'; + parser->completion_quote_end = NULL;; + } + } + parser->lexer.current.type = LSTOKEN_CONSUMED; - return linespec_lexer_lex_one (parser); + linespec_lexer_lex_one (parser); + + if (parser->lexer.current.type == LSTOKEN_STRING) + { + /* Advance the completion word past a potential initial + quote-char. */ + parser->completion_word = LS_TOKEN_STOKEN (parser->lexer.current).ptr; + } + else if (advance_word) + { + /* Advance the completion word past any whitespace. */ + parser->completion_word = PARSER_STREAM (parser); + } + + return parser->lexer.current; } /* Return the next token without consuming the current token. */ @@ -794,26 +993,21 @@ linespec_lexer_peek_token (linespec_parser *parser) linespec_token next; const char *saved_stream = PARSER_STREAM (parser); linespec_token saved_token = parser->lexer.current; + int saved_completion_quote_char = parser->completion_quote_char; + const char *saved_completion_quote_end = parser->completion_quote_end; + const char *saved_completion_word = parser->completion_word; next = linespec_lexer_consume_token (parser); PARSER_STREAM (parser) = saved_stream; parser->lexer.current = saved_token; + parser->completion_quote_char = saved_completion_quote_char; + parser->completion_quote_end = saved_completion_quote_end; + parser->completion_word = saved_completion_word; return next; } /* Helper functions. */ -/* Add SAL to SALS. */ - -static void -add_sal_to_sals_basic (struct symtabs_and_lines *sals, - struct symtab_and_line *sal) -{ - ++sals->nelts; - sals->sals = xrealloc (sals->sals, sals->nelts * sizeof (sals->sals[0])); - sals->sals[sals->nelts - 1] = *sal; -} - /* Add SAL to SALS, and also update SELF->CANONICAL_NAMES to reflect the new sal, if needed. If not NULL, SYMNAME is the name of the symbol to use when constructing the new canonical name. @@ -823,23 +1017,23 @@ add_sal_to_sals_basic (struct symtabs_and_lines *sals, static void add_sal_to_sals (struct linespec_state *self, - struct symtabs_and_lines *sals, + std::vector *sals, struct symtab_and_line *sal, const char *symname, int literal_canonical) { - add_sal_to_sals_basic (sals, sal); + sals->push_back (*sal); if (self->canonical) { struct linespec_canonical_name *canonical; - self->canonical_names = xrealloc (self->canonical_names, - (sals->nelts - * sizeof (*self->canonical_names))); - canonical = &self->canonical_names[sals->nelts - 1]; + self->canonical_names = XRESIZEVEC (struct linespec_canonical_name, + self->canonical_names, + sals->size ()); + canonical = &self->canonical_names[sals->size () - 1]; if (!literal_canonical && sal->symtab) { - const char *fullname = symtab_to_fullname (sal->symtab); + symtab_to_fullname (sal->symtab); /* Note that the filter doesn't have to be a valid linespec input. We only apply the ":LINE" treatment to Ada for @@ -869,7 +1063,7 @@ add_sal_to_sals (struct linespec_state *self, static hashval_t hash_address_entry (const void *p) { - const struct address_entry *aep = p; + const struct address_entry *aep = (const struct address_entry *) p; hashval_t hash; hash = iterative_hash_object (aep->pspace, 0); @@ -881,8 +1075,8 @@ hash_address_entry (const void *p) static int eq_address_entry (const void *a, const void *b) { - const struct address_entry *aea = a; - const struct address_entry *aeb = b; + const struct address_entry *aea = (const struct address_entry *) a; + const struct address_entry *aeb = (const struct address_entry *) b; return aea->pspace == aeb->pspace && aea->addr == aeb->addr; } @@ -910,81 +1104,23 @@ maybe_add_address (htab_t set, struct program_space *pspace, CORE_ADDR addr) return 1; } -/* A callback function and the additional data to call it with. */ - -struct symbol_and_data_callback -{ - /* The callback to use. */ - symbol_found_callback_ftype *callback; - - /* Data to be passed to the callback. */ - void *data; -}; - -/* A helper for iterate_over_all_matching_symtabs that is used to - restrict calls to another callback to symbols representing inline - symbols only. */ - -static int -iterate_inline_only (struct symbol *sym, void *d) -{ - if (SYMBOL_INLINED (sym)) - { - struct symbol_and_data_callback *cad = d; - - return cad->callback (sym, cad->data); - } - return 1; /* Continue iterating. */ -} - -/* Some data for the expand_symtabs_matching callback. */ - -struct symbol_matcher_data -{ - /* The lookup name against which symbol name should be compared. */ - const char *lookup_name; - - /* The routine to be used for comparison. */ - symbol_name_cmp_ftype symbol_name_cmp; -}; - -/* A helper for iterate_over_all_matching_symtabs that is passed as a - callback to the expand_symtabs_matching method. */ - -static int -iterate_name_matcher (const char *name, void *d) -{ - const struct symbol_matcher_data *data = d; - - if (data->symbol_name_cmp (name, data->lookup_name) == 0) - return 1; /* Expand this symbol's symbol table. */ - return 0; /* Skip this symbol. */ -} - /* A helper that walks over all matching symtabs in all objfiles and calls CALLBACK for each symbol matching NAME. If SEARCH_PSPACE is not NULL, then the search is restricted to just that program - space. If INCLUDE_INLINE is nonzero then symbols representing + space. If INCLUDE_INLINE is true then symbols representing inlined instances of functions will be included in the result. */ static void -iterate_over_all_matching_symtabs (struct linespec_state *state, - const char *name, - const domain_enum domain, - symbol_found_callback_ftype *callback, - void *data, - struct program_space *search_pspace, - int include_inline) +iterate_over_all_matching_symtabs + (struct linespec_state *state, + const lookup_name_info &lookup_name, + const domain_enum name_domain, + enum search_domain search_domain, + struct program_space *search_pspace, bool include_inline, + gdb::function_view callback) { struct objfile *objfile; struct program_space *pspace; - struct symbol_matcher_data matcher_data; - - matcher_data.lookup_name = name; - matcher_data.symbol_name_cmp = - state->language->la_get_symbol_name_cmp != NULL - ? state->language->la_get_symbol_name_cmp (name) - : strcmp_iw; ALL_PSPACES (pspace) { @@ -1000,20 +1136,20 @@ iterate_over_all_matching_symtabs (struct linespec_state *state, struct compunit_symtab *cu; if (objfile->sf) - objfile->sf->qf->expand_symtabs_matching (objfile, NULL, - iterate_name_matcher, - NULL, ALL_DOMAIN, - &matcher_data); + objfile->sf->qf->expand_symtabs_matching (objfile, + NULL, + lookup_name, + NULL, NULL, + search_domain); ALL_OBJFILE_COMPUNITS (objfile, cu) { struct symtab *symtab = COMPUNIT_FILETABS (cu); - iterate_over_file_blocks (symtab, name, domain, callback, data); + iterate_over_file_blocks (symtab, lookup_name, name_domain, callback); if (include_inline) { - struct symbol_and_data_callback cad = { callback, data }; struct block *block; int i; @@ -1023,7 +1159,14 @@ iterate_over_all_matching_symtabs (struct linespec_state *state, { block = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (symtab), i); state->language->la_iterate_over_symbols - (block, name, domain, iterate_inline_only, &cad); + (block, lookup_name, name_domain, [&] (symbol *sym) + { + /* Restrict calls to CALLBACK to symbols + representing inline symbols only. */ + if (SYMBOL_INLINED (sym)) + return callback (sym); + return true; + }); } } } @@ -1052,24 +1195,24 @@ get_current_search_block (void) /* Iterate over static and global blocks. */ static void -iterate_over_file_blocks (struct symtab *symtab, - const char *name, domain_enum domain, - symbol_found_callback_ftype *callback, void *data) +iterate_over_file_blocks + (struct symtab *symtab, const lookup_name_info &name, + domain_enum domain, gdb::function_view callback) { struct block *block; for (block = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (symtab), STATIC_BLOCK); block != NULL; block = BLOCK_SUPERBLOCK (block)) - LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data); + LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback); } -/* A helper for find_method. This finds all methods in type T which - match NAME. It adds matching symbol names to RESULT_NAMES, and - adds T's direct superclasses to SUPERCLASSES. */ +/* A helper for find_method. This finds all methods in type T of + language T_LANG which match NAME. It adds matching symbol names to + RESULT_NAMES, and adds T's direct superclasses to SUPERCLASSES. */ static void -find_methods (struct type *t, const char *name, +find_methods (struct type *t, enum language t_lang, const char *name, VEC (const_char_ptr) **result_names, VEC (typep) **superclasses) { @@ -1082,6 +1225,9 @@ find_methods (struct type *t, const char *name, if (class_name) { int method_counter; + lookup_name_info lookup_name (name, symbol_name_match_type::FULL); + symbol_name_matcher_ftype *symbol_name_compare + = get_symbol_name_matcher (language_def (t_lang), lookup_name); t = check_typedef (t); @@ -1106,7 +1252,7 @@ find_methods (struct type *t, const char *name, method_name = dem_opname; } - if (strcmp_iw (method_name, name) == 0) + if (symbol_name_compare (method_name, lookup_name, NULL)) { int field_counter; @@ -1135,7 +1281,7 @@ find_methods (struct type *t, const char *name, /* 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. */ + within foo, while considering C++ operator') && depth > 0) depth--; + else if (*scan == 'o' && !quoted && depth == 0) + { + /* Handle C++ operator names. */ + if (strncmp (scan, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0) + { + scan += CP_OPERATOR_LEN; + if (*scan == c) + return scan; + while (isspace (*scan)) + { + ++scan; + if (*scan == c) + return scan; + } + if (*scan == '\0') + break; + + switch (*scan) + { + /* Skip over one less than the appropriate number of + characters: the for loop will skip over the last + one. */ + case '<': + if (scan[1] == '<') + { + scan++; + if (*scan == c) + return scan; + } + break; + case '>': + if (scan[1] == '>') + { + scan++; + if (*scan == c) + return scan; + } + break; + } + } + } } return 0; @@ -1216,7 +1403,7 @@ canonical_to_fullform (const struct linespec_canonical_name *canonical) static void filter_results (struct linespec_state *self, - struct symtabs_and_lines *result, + std::vector *result, VEC (const_char_ptr) *filters) { int i; @@ -1224,12 +1411,9 @@ filter_results (struct linespec_state *self, for (i = 0; VEC_iterate (const_char_ptr, filters, i, name); ++i) { - struct linespec_sals lsal; - int j; - - memset (&lsal, 0, sizeof (lsal)); + linespec_sals lsal; - for (j = 0; j < result->nelts; ++j) + for (size_t j = 0; j < result->size (); ++j) { const struct linespec_canonical_name *canonical; char *fullform; @@ -1240,15 +1424,15 @@ filter_results (struct linespec_state *self, cleanup = make_cleanup (xfree, fullform); if (strcmp (name, fullform) == 0) - add_sal_to_sals_basic (&lsal.sals, &result->sals[j]); + lsal.sals.push_back ((*result)[j]); do_cleanups (cleanup); } - if (lsal.sals.nelts > 0) + if (!lsal.sals.empty ()) { lsal.canonical = xstrdup (name); - VEC_safe_push (linespec_sals, self->canonical->sals, &lsal); + self->canonical->lsals.push_back (std::move (lsal)); } } @@ -1259,13 +1443,13 @@ filter_results (struct linespec_state *self, static void convert_results_to_lsals (struct linespec_state *self, - struct symtabs_and_lines *result) + std::vector *result) { struct linespec_sals lsal; lsal.canonical = NULL; - lsal.sals = *result; - VEC_safe_push (linespec_sals, self->canonical->sals, &lsal); + lsal.sals = std::move (*result); + self->canonical->lsals.push_back (std::move (lsal)); } /* A structure that contains two string representations of a struct @@ -1295,8 +1479,8 @@ struct decode_line_2_item static int decode_line_2_compare_items (const void *ap, const void *bp) { - const struct decode_line_2_item *a = ap; - const struct decode_line_2_item *b = bp; + const struct decode_line_2_item *a = (const struct decode_line_2_item *) ap; + const struct decode_line_2_item *b = (const struct decode_line_2_item *) bp; int retval; retval = strcmp (a->displayform, b->displayform); @@ -1313,25 +1497,25 @@ decode_line_2_compare_items (const void *ap, const void *bp) static void decode_line_2 (struct linespec_state *self, - struct symtabs_and_lines *result, + std::vector *result, const char *select_mode) { - char *args, *prompt; + char *args; + const char *prompt; int i; struct cleanup *old_chain; VEC (const_char_ptr) *filters = NULL; - struct get_number_or_range_state state; struct decode_line_2_item *items; int items_count; gdb_assert (select_mode != multiple_symbols_all); gdb_assert (self->canonical != NULL); - gdb_assert (result->nelts >= 1); + gdb_assert (!result->empty ()); old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &filters); /* Prepare ITEMS array. */ - items_count = result->nelts; + items_count = result->size (); items = XNEWVEC (struct decode_line_2_item, items_count); make_cleanup (xfree, items); for (i = 0; i < items_count; ++i) @@ -1401,12 +1585,10 @@ decode_line_2 (struct linespec_state *self, if (args == 0 || *args == 0) error_no_arg (_("one or more choice numbers")); - init_number_or_range (&state, args); - while (!state.finished) + number_or_range_parser parser (args); + while (!parser.finished ()) { - int num; - - num = get_number_or_range (&state); + int num = parser.get_number (); if (num == 0) error (_("canceled")); @@ -1511,10 +1693,9 @@ unexpected_linespec_error (linespec_parser *parser) || token.type == LSTOKEN_KEYWORD) { char *string; - struct cleanup *cleanup; string = copy_token_string (token); - cleanup = make_cleanup (xfree, string); + make_cleanup (xfree, string); throw_error (GENERIC_ERROR, _("malformed linespec error: unexpected %s, \"%s\""), token_type_strings[token.type], string); @@ -1548,6 +1729,17 @@ source_file_not_found_error (const char *name) throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name); } +/* Unless at EIO, save the current stream position as completion word + point, and consume the next token. */ + +static linespec_token +save_stream_and_consume_token (linespec_parser *parser) +{ + if (linespec_lexer_peek_token (parser).type != LSTOKEN_EOI) + parser->completion_word = PARSER_STREAM (parser); + return linespec_lexer_consume_token (parser); +} + /* See description in linespec.h. */ struct line_offset @@ -1575,6 +1767,26 @@ linespec_parse_line_offset (const char *string) return line_offset; } +/* In completion mode, if the user is still typing the number, there's + no possible completion to offer. But if there's already input past + the number, setup to expect NEXT. */ + +static void +set_completion_after_number (linespec_parser *parser, + linespec_complete_what next) +{ + if (*PARSER_STREAM (parser) == ' ') + { + parser->completion_word = skip_spaces (PARSER_STREAM (parser) + 1); + parser->complete_what = next; + } + else + { + parser->completion_word = PARSER_STREAM (parser); + parser->complete_what = linespec_complete_what::NOTHING; + } +} + /* Parse the basic_spec in PARSER's input. */ static void @@ -1590,11 +1802,20 @@ linespec_parse_basic (linespec_parser *parser) token = linespec_lexer_lex_one (parser); /* If it is EOI or KEYWORD, issue an error. */ - if (token.type == LSTOKEN_KEYWORD || token.type == LSTOKEN_EOI) - unexpected_linespec_error (parser); + if (token.type == LSTOKEN_KEYWORD) + { + parser->complete_what = linespec_complete_what::NOTHING; + unexpected_linespec_error (parser); + } + else if (token.type == LSTOKEN_EOI) + { + unexpected_linespec_error (parser); + } /* If it is a LSTOKEN_NUMBER, we have an offset. */ else if (token.type == LSTOKEN_NUMBER) { + set_completion_after_number (parser, linespec_complete_what::KEYWORD); + /* Record the line offset and get the next token. */ name = copy_token_string (token); cleanup = make_cleanup (xfree, name); @@ -1606,7 +1827,10 @@ linespec_parse_basic (linespec_parser *parser) /* If the next token is a comma, stop parsing and return. */ if (token.type == LSTOKEN_COMMA) - return; + { + parser->complete_what = linespec_complete_what::NOTHING; + return; + } /* If the next token is anything but EOI or KEYWORD, issue an error. */ @@ -1619,76 +1843,132 @@ linespec_parse_basic (linespec_parser *parser) /* Next token must be LSTOKEN_STRING. */ if (token.type != LSTOKEN_STRING) - unexpected_linespec_error (parser); + { + parser->complete_what = linespec_complete_what::NOTHING; + unexpected_linespec_error (parser); + } /* The current token will contain the name of a function, method, or label. */ - name = copy_token_string (token); - cleanup = make_cleanup (xfree, name); + name = copy_token_string (token); + cleanup = make_cleanup (free_current_contents, &name); - /* Try looking it up as a function/method. */ - find_linespec_symbols (PARSER_STATE (parser), - PARSER_RESULT (parser)->file_symtabs, name, - &symbols, &minimal_symbols); - - if (symbols != NULL || minimal_symbols != NULL) + if (parser->completion_tracker != NULL) { - PARSER_RESULT (parser)->function_symbols = symbols; - PARSER_RESULT (parser)->minimal_symbols = minimal_symbols; + /* If the function name ends with a ":", then this may be an + incomplete "::" scope operator instead of a label separator. + E.g., + "b klass:" + which should expand to: + "b klass::method()" + + Do a tentative completion assuming the later. If we find + completions, advance the stream past the colon token and make + it part of the function name/token. */ + + if (!parser->completion_quote_char + && strcmp (PARSER_STREAM (parser), ":") == 0) + { + completion_tracker tmp_tracker; + const char *source_filename + = PARSER_EXPLICIT (parser)->source_filename; + symbol_name_match_type match_type + = PARSER_EXPLICIT (parser)->func_name_match_type; + + linespec_complete_function (tmp_tracker, + parser->completion_word, + match_type, + source_filename); + + if (tmp_tracker.have_completions ()) + { + PARSER_STREAM (parser)++; + LS_TOKEN_STOKEN (token).length++; + + xfree (name); + name = savestring (parser->completion_word, + (PARSER_STREAM (parser) + - parser->completion_word)); + } + } + PARSER_EXPLICIT (parser)->function_name = name; - symbols = NULL; discard_cleanups (cleanup); } else { - /* NAME was not a function or a method. So it must be a label - name or user specified variable like "break foo.c:$zippo". */ - labels = find_label_symbols (PARSER_STATE (parser), NULL, - &symbols, name); - if (labels != NULL) + /* Try looking it up as a function/method. */ + find_linespec_symbols (PARSER_STATE (parser), + PARSER_RESULT (parser)->file_symtabs, name, + PARSER_EXPLICIT (parser)->func_name_match_type, + &symbols, &minimal_symbols); + + if (symbols != NULL || minimal_symbols != NULL) { - PARSER_RESULT (parser)->labels.label_symbols = labels; - PARSER_RESULT (parser)->labels.function_symbols = symbols; - PARSER_EXPLICIT (parser)->label_name = name; + PARSER_RESULT (parser)->function_symbols = symbols; + PARSER_RESULT (parser)->minimal_symbols = minimal_symbols; + PARSER_EXPLICIT (parser)->function_name = name; symbols = NULL; discard_cleanups (cleanup); } - else if (token.type == LSTOKEN_STRING - && *LS_TOKEN_STOKEN (token).ptr == '$') + else { - /* User specified a convenience variable or history value. */ - PARSER_EXPLICIT (parser)->line_offset - = linespec_parse_variable (PARSER_STATE (parser), name); + /* NAME was not a function or a method. So it must be a label + name or user specified variable like "break foo.c:$zippo". */ + labels = find_label_symbols (PARSER_STATE (parser), NULL, + &symbols, name); + if (labels != NULL) + { + PARSER_RESULT (parser)->labels.label_symbols = labels; + PARSER_RESULT (parser)->labels.function_symbols = symbols; + PARSER_EXPLICIT (parser)->label_name = name; + symbols = NULL; + discard_cleanups (cleanup); + } + else if (token.type == LSTOKEN_STRING + && *LS_TOKEN_STOKEN (token).ptr == '$') + { + /* User specified a convenience variable or history value. */ + PARSER_EXPLICIT (parser)->line_offset + = linespec_parse_variable (PARSER_STATE (parser), name); + + if (PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN) + { + /* The user-specified variable was not valid. Do not + throw an error here. parse_linespec will do it for us. */ + PARSER_EXPLICIT (parser)->function_name = name; + discard_cleanups (cleanup); + return; + } - if (PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN) + /* The convenience variable/history value parsed correctly. + NAME is no longer needed. */ + do_cleanups (cleanup); + } + else { - /* The user-specified variable was not valid. Do not - throw an error here. parse_linespec will do it for us. */ + /* The name is also not a label. Abort parsing. Do not throw + an error here. parse_linespec will do it for us. */ + + /* Save a copy of the name we were trying to lookup. */ PARSER_EXPLICIT (parser)->function_name = name; discard_cleanups (cleanup); return; } - - /* The convenience variable/history value parsed correctly. - NAME is no longer needed. */ - do_cleanups (cleanup); - } - else - { - /* The name is also not a label. Abort parsing. Do not throw - an error here. parse_linespec will do it for us. */ - - /* Save a copy of the name we were trying to lookup. */ - PARSER_EXPLICIT (parser)->function_name = name; - discard_cleanups (cleanup); - return; } } + int previous_qc = parser->completion_quote_char; + /* Get the next token. */ token = linespec_lexer_consume_token (parser); - if (token.type == LSTOKEN_COLON) + if (token.type == LSTOKEN_EOI) + { + if (previous_qc && !parser->completion_quote_char) + parser->complete_what = linespec_complete_what::KEYWORD; + } + else if (token.type == LSTOKEN_COLON) { /* User specified a label or a lineno. */ token = linespec_lexer_consume_token (parser); @@ -1697,41 +1977,81 @@ linespec_parse_basic (linespec_parser *parser) { /* User specified an offset. Record the line offset and get the next token. */ + set_completion_after_number (parser, linespec_complete_what::KEYWORD); + name = copy_token_string (token); cleanup = make_cleanup (xfree, name); PARSER_EXPLICIT (parser)->line_offset = linespec_parse_line_offset (name); do_cleanups (cleanup); - /* Ge the next token. */ + /* Get the next token. */ token = linespec_lexer_consume_token (parser); } + else if (token.type == LSTOKEN_EOI && parser->completion_tracker != NULL) + { + parser->complete_what = linespec_complete_what::LABEL; + } else if (token.type == LSTOKEN_STRING) { - /* Grab a copy of the label's name and look it up. */ - name = copy_token_string (token); - cleanup = make_cleanup (xfree, name); - labels = find_label_symbols (PARSER_STATE (parser), - PARSER_RESULT (parser)->function_symbols, - &symbols, name); + parser->complete_what = linespec_complete_what::LABEL; + + /* If we have text after the label separated by whitespace + (e.g., "b func():lab i"), don't consider it part of + the label. In completion mode that should complete to + "if", in normal mode, the 'i' should be treated as + garbage. */ + if (parser->completion_quote_char == '\0') + { + const char *ptr = LS_TOKEN_STOKEN (token).ptr; + for (size_t i = 0; i < LS_TOKEN_STOKEN (token).length; i++) + { + if (ptr[i] == ' ') + { + LS_TOKEN_STOKEN (token).length = i; + PARSER_STREAM (parser) = skip_spaces (ptr + i + 1); + break; + } + } + } - if (labels != NULL) + if (parser->completion_tracker != NULL) { - PARSER_RESULT (parser)->labels.label_symbols = labels; - PARSER_RESULT (parser)->labels.function_symbols = symbols; - PARSER_EXPLICIT (parser)->label_name = name; - symbols = NULL; - discard_cleanups (cleanup); + if (PARSER_STREAM (parser)[-1] == ' ') + { + parser->completion_word = PARSER_STREAM (parser); + parser->complete_what = linespec_complete_what::KEYWORD; + } } else { - /* We don't know what it was, but it isn't a label. */ - undefined_label_error (PARSER_EXPLICIT (parser)->function_name, - name); + /* Grab a copy of the label's name and look it up. */ + name = copy_token_string (token); + cleanup = make_cleanup (xfree, name); + labels + = find_label_symbols (PARSER_STATE (parser), + PARSER_RESULT (parser)->function_symbols, + &symbols, name); + + if (labels != NULL) + { + PARSER_RESULT (parser)->labels.label_symbols = labels; + PARSER_RESULT (parser)->labels.function_symbols = symbols; + PARSER_EXPLICIT (parser)->label_name = name; + symbols = NULL; + discard_cleanups (cleanup); + } + else + { + /* We don't know what it was, but it isn't a label. */ + undefined_label_error + (PARSER_EXPLICIT (parser)->function_name, name); + } + } /* Check for a line offset. */ - token = linespec_lexer_consume_token (parser); + token = save_stream_and_consume_token (parser); if (token.type == LSTOKEN_COLON) { /* Get the next token. */ @@ -1741,7 +2061,7 @@ linespec_parse_basic (linespec_parser *parser) if (token.type != LSTOKEN_NUMBER) unexpected_linespec_error (parser); - /* Record the lione offset and get the next token. */ + /* Record the line offset and get the next token. */ name = copy_token_string (token); cleanup = make_cleanup (xfree, name); @@ -1776,8 +2096,9 @@ canonicalize_linespec (struct linespec_state *state, const linespec_p ls) return; /* Save everything as an explicit location. */ - canon = state->canonical->location + state->canonical->location = new_explicit_location (&ls->explicit_loc); + canon = state->canonical->location.get (); explicit_loc = get_explicit_location (canon); if (explicit_loc->label_name != NULL) @@ -1810,18 +2131,12 @@ canonicalize_linespec (struct linespec_state *state, const linespec_p ls) /* Given a line offset in LS, construct the relevant SALs. */ -static struct symtabs_and_lines +static std::vector create_sals_line_offset (struct linespec_state *self, linespec_p ls) { - struct symtabs_and_lines values; - struct symtab_and_line val; int use_default = 0; - init_sal (&val); - values.sals = NULL; - values.nelts = 0; - /* This is where we need to make sure we have good defaults. We must guarantee that this section of code is never executed when we are called with just a function name, since @@ -1841,10 +2156,12 @@ create_sals_line_offset (struct linespec_state *self, fullname = symtab_to_fullname (self->default_symtab); VEC_pop (symtab_ptr, ls->file_symtabs); VEC_free (symtab_ptr, ls->file_symtabs); - ls->file_symtabs = collect_symtabs_from_filename (fullname); + ls->file_symtabs = collect_symtabs_from_filename (fullname, + self->search_pspace); use_default = 1; } + symtab_and_line val; val.line = ls->explicit_loc.line_offset.offset; switch (ls->explicit_loc.line_offset.sign) { @@ -1868,27 +2185,20 @@ create_sals_line_offset (struct linespec_state *self, break; /* No need to adjust val.line. */ } + std::vector values; if (self->list_mode) - decode_digits_list_mode (self, ls, &values, val); + values = decode_digits_list_mode (self, ls, val); else { struct linetable_entry *best_entry = NULL; - int *filter; - const struct block **blocks; - struct cleanup *cleanup; - struct symtabs_and_lines intermediate_results; int i, j; - intermediate_results.sals = NULL; - intermediate_results.nelts = 0; - - decode_digits_ordinary (self, ls, val.line, &intermediate_results, - &best_entry); - if (intermediate_results.nelts == 0 && best_entry != NULL) - decode_digits_ordinary (self, ls, best_entry->line, - &intermediate_results, &best_entry); - - cleanup = make_cleanup (xfree, intermediate_results.sals); + std::vector intermediate_results + = decode_digits_ordinary (self, ls, val.line, &best_entry); + if (intermediate_results.empty () && best_entry != NULL) + intermediate_results = decode_digits_ordinary (self, ls, + best_entry->line, + &best_entry); /* For optimized code, the compiler can scatter one source line across disjoint ranges of PC values, even when no duplicate @@ -1900,24 +2210,22 @@ create_sals_line_offset (struct linespec_state *self, above, we see if there are other PCs that are in the same block. If yes, the other PCs are filtered out. */ - filter = XNEWVEC (int, intermediate_results.nelts); - make_cleanup (xfree, filter); - blocks = XNEWVEC (const struct block *, intermediate_results.nelts); - make_cleanup (xfree, blocks); + gdb::def_vector filter (intermediate_results.size ()); + gdb::def_vector blocks (intermediate_results.size ()); - for (i = 0; i < intermediate_results.nelts; ++i) + for (i = 0; i < intermediate_results.size (); ++i) { - set_current_program_space (intermediate_results.sals[i].pspace); + set_current_program_space (intermediate_results[i].pspace); filter[i] = 1; - blocks[i] = block_for_pc_sect (intermediate_results.sals[i].pc, - intermediate_results.sals[i].section); + blocks[i] = block_for_pc_sect (intermediate_results[i].pc, + intermediate_results[i].section); } - for (i = 0; i < intermediate_results.nelts; ++i) + for (i = 0; i < intermediate_results.size (); ++i) { if (blocks[i] != NULL) - for (j = i + 1; j < intermediate_results.nelts; ++j) + for (j = i + 1; j < intermediate_results.size (); ++j) { if (blocks[j] == blocks[i]) { @@ -1927,7 +2235,7 @@ create_sals_line_offset (struct linespec_state *self, } } - for (i = 0; i < intermediate_results.nelts; ++i) + for (i = 0; i < intermediate_results.size (); ++i) if (filter[i]) { struct symbol *sym = (blocks[i] @@ -1935,18 +2243,13 @@ create_sals_line_offset (struct linespec_state *self, : NULL); if (self->funfirstline) - skip_prologue_sal (&intermediate_results.sals[i]); - /* Make sure the line matches the request, not what was - found. */ - intermediate_results.sals[i].line = val.line; - add_sal_to_sals (self, &values, &intermediate_results.sals[i], + skip_prologue_sal (&intermediate_results[i]); + add_sal_to_sals (self, &values, &intermediate_results[i], sym ? SYMBOL_NATURAL_NAME (sym) : NULL, 0); } - - do_cleanups (cleanup); } - if (values.nelts == 0) + if (values.empty ()) { if (ls->explicit_loc.source_filename) throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."), @@ -1961,17 +2264,16 @@ create_sals_line_offset (struct linespec_state *self, /* Convert the given ADDRESS into SaLs. */ -static struct symtabs_and_lines +static std::vector convert_address_location_to_sals (struct linespec_state *self, CORE_ADDR address) { - struct symtab_and_line sal; - struct symtabs_and_lines sals = {NULL, 0}; - - sal = find_pc_line (address, 0); + symtab_and_line sal = find_pc_line (address, 0); sal.pc = address; sal.section = find_pc_overlay (address); sal.explicit_pc = 1; + + std::vector sals; add_sal_to_sals (self, &sals, &sal, core_addr_to_string (address), 1); return sals; @@ -1979,10 +2281,10 @@ convert_address_location_to_sals (struct linespec_state *self, /* Create and return SALs from the linespec LS. */ -static struct symtabs_and_lines +static std::vector convert_linespec_to_sals (struct linespec_state *state, linespec_p ls) { - struct symtabs_and_lines sals = {NULL, 0}; + std::vector sals; if (ls->labels.label_symbols != NULL) { @@ -2072,36 +2374,42 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls) canonicalize_linespec (state, ls); - if (sals.nelts > 0 && state->canonical != NULL) + if (!sals.empty () && state->canonical != NULL) state->canonical->pre_expanded = 1; return sals; } -/* Convert the explicit location EXPLICIT_LOC into SaLs. */ +/* Build RESULT from the explicit location components SOURCE_FILENAME, + FUNCTION_NAME, LABEL_NAME and LINE_OFFSET. */ -static struct symtabs_and_lines -convert_explicit_location_to_sals (struct linespec_state *self, - linespec_p result, - const struct explicit_location *explicit_loc) +static void +convert_explicit_location_to_linespec (struct linespec_state *self, + linespec_p result, + const char *source_filename, + const char *function_name, + symbol_name_match_type fname_match_type, + const char *label_name, + struct line_offset line_offset) { VEC (symbolp) *symbols, *labels; VEC (bound_minimal_symbol_d) *minimal_symbols; - if (explicit_loc->source_filename != NULL) + result->explicit_loc.func_name_match_type = fname_match_type; + + if (source_filename != NULL) { TRY { result->file_symtabs - = symtabs_from_filename (explicit_loc->source_filename); + = symtabs_from_filename (source_filename, self->search_pspace); } CATCH (except, RETURN_MASK_ERROR) { - source_file_not_found_error (explicit_loc->source_filename); + source_file_not_found_error (source_filename); } END_CATCH - result->explicit_loc.source_filename - = xstrdup (explicit_loc->source_filename); + result->explicit_loc.source_filename = xstrdup (source_filename); } else { @@ -2109,41 +2417,54 @@ convert_explicit_location_to_sals (struct linespec_state *self, VEC_safe_push (symtab_ptr, result->file_symtabs, NULL); } - if (explicit_loc->function_name != NULL) + if (function_name != NULL) { find_linespec_symbols (self, result->file_symtabs, - explicit_loc->function_name, &symbols, - &minimal_symbols); + function_name, fname_match_type, + &symbols, &minimal_symbols); if (symbols == NULL && minimal_symbols == NULL) - symbol_not_found_error (explicit_loc->function_name, + symbol_not_found_error (function_name, result->explicit_loc.source_filename); - result->explicit_loc.function_name - = xstrdup (explicit_loc->function_name); + result->explicit_loc.function_name = xstrdup (function_name); result->function_symbols = symbols; result->minimal_symbols = minimal_symbols; } - if (explicit_loc->label_name != NULL) + if (label_name != NULL) { symbols = NULL; labels = find_label_symbols (self, result->function_symbols, - &symbols, explicit_loc->label_name); + &symbols, label_name); if (labels == NULL) undefined_label_error (result->explicit_loc.function_name, - explicit_loc->label_name); + label_name); - result->explicit_loc.label_name = xstrdup (explicit_loc->label_name); + result->explicit_loc.label_name = xstrdup (label_name); result->labels.label_symbols = labels; result->labels.function_symbols = symbols; } - if (explicit_loc->line_offset.sign != LINE_OFFSET_UNKNOWN) - result->explicit_loc.line_offset = explicit_loc->line_offset; + if (line_offset.sign != LINE_OFFSET_UNKNOWN) + result->explicit_loc.line_offset = line_offset; +} + +/* Convert the explicit location EXPLICIT_LOC into SaLs. */ - return convert_linespec_to_sals (self, result); +static std::vector +convert_explicit_location_to_sals (struct linespec_state *self, + linespec_p result, + const struct explicit_location *explicit_loc) +{ + convert_explicit_location_to_linespec (self, result, + explicit_loc->source_filename, + explicit_loc->function_name, + explicit_loc->func_name_match_type, + explicit_loc->label_name, + explicit_loc->line_offset); + return convert_linespec_to_sals (self, result); } /* Parse a string that specifies a linespec. @@ -2194,13 +2515,14 @@ convert_explicit_location_to_sals (struct linespec_state *self, if no file is validly specified. Callers must check that. Also, the line number returned may be invalid. */ -/* Parse the linespec in ARG. */ +/* Parse the linespec in ARG. MATCH_TYPE indicates how function names + should be matched. */ -static struct symtabs_and_lines -parse_linespec (linespec_parser *parser, const char *arg) +static std::vector +parse_linespec (linespec_parser *parser, const char *arg, + symbol_name_match_type match_type) { linespec_token token; - struct symtabs_and_lines values; struct gdb_exception file_exception = exception_none; struct cleanup *cleanup; @@ -2208,7 +2530,8 @@ parse_linespec (linespec_parser *parser, const char *arg) IDEs to work around bugs in the previous parser by quoting the entire linespec, so we attempt to deal with this nicely. */ parser->is_quote_enclosed = 0; - if (!is_ada_operator (arg) + if (parser->completion_tracker == NULL + && !is_ada_operator (arg) && strchr (linespec_quote_characters, *arg) != NULL) { const char *end; @@ -2225,20 +2548,36 @@ parse_linespec (linespec_parser *parser, const char *arg) parser->lexer.saved_arg = arg; parser->lexer.stream = arg; + parser->completion_word = arg; + parser->complete_what = linespec_complete_what::FUNCTION; + PARSER_EXPLICIT (parser)->func_name_match_type = match_type; /* Initialize the default symtab and line offset. */ initialize_defaults (&PARSER_STATE (parser)->default_symtab, &PARSER_STATE (parser)->default_line); /* Objective-C shortcut. */ - values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg); - if (values.sals != NULL) - return values; + if (parser->completion_tracker == NULL) + { + std::vector values + = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg); + if (!values.empty ()) + return values; + } + else + { + /* "-"/"+" is either an objc selector, or a number. There's + nothing to complete the latter to, so just let the caller + complete on functions, which finds objc selectors, if there's + any. */ + if ((arg[0] == '-' || arg[0] == '+') && arg[1] == '\0') + return {}; + } /* Start parsing. */ /* Get the first token. */ - token = linespec_lexer_lex_one (parser); + token = linespec_lexer_consume_token (parser); /* It must be either LSTOKEN_STRING or LSTOKEN_NUMBER. */ if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '$') @@ -2246,7 +2585,8 @@ parse_linespec (linespec_parser *parser, const char *arg) char *var; /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */ - VEC_safe_push (symtab_ptr, PARSER_RESULT (parser)->file_symtabs, NULL); + if (parser->completion_tracker == NULL) + VEC_safe_push (symtab_ptr, PARSER_RESULT (parser)->file_symtabs, NULL); /* User specified a convenience variable or history value. */ var = copy_token_string (token); @@ -2265,8 +2605,16 @@ parse_linespec (linespec_parser *parser, const char *arg) goto convert_to_sals; } } + else if (token.type == LSTOKEN_EOI && parser->completion_tracker != NULL) + { + /* Let the default linespec_complete_what::FUNCTION kick in. */ + unexpected_linespec_error (parser); + } else if (token.type != LSTOKEN_STRING && token.type != LSTOKEN_NUMBER) - unexpected_linespec_error (parser); + { + parser->complete_what = linespec_complete_what::NOTHING; + unexpected_linespec_error (parser); + } /* Shortcut: If the next token is not LSTOKEN_COLON, we know that this token cannot represent a filename. */ @@ -2284,7 +2632,8 @@ parse_linespec (linespec_parser *parser, const char *arg) TRY { PARSER_RESULT (parser)->file_symtabs - = symtabs_from_filename (user_filename); + = symtabs_from_filename (user_filename, + PARSER_STATE (parser)->search_pspace); } CATCH (ex, RETURN_MASK_ERROR) { @@ -2313,8 +2662,9 @@ parse_linespec (linespec_parser *parser, const char *arg) } } /* If the next token is not EOI, KEYWORD, or COMMA, issue an error. */ - else if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD - && token.type != LSTOKEN_COMMA) + else if (parser->completion_tracker == NULL + && (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD + && token.type != LSTOKEN_COMMA)) { /* TOKEN is the _next_ token, not the one currently in the parser. Consuming the token will give the correct error message. */ @@ -2330,7 +2680,8 @@ parse_linespec (linespec_parser *parser, const char *arg) /* Parse the rest of the linespec. */ linespec_parse_basic (parser); - if (PARSER_RESULT (parser)->function_symbols == NULL + if (parser->completion_tracker == NULL + && PARSER_RESULT (parser)->function_symbols == NULL && PARSER_RESULT (parser)->labels.label_symbols == NULL && PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN && PARSER_RESULT (parser)->minimal_symbols == NULL) @@ -2351,13 +2702,23 @@ parse_linespec (linespec_parser *parser, const char *arg) if necessary. */ token = linespec_lexer_lex_one (parser); if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD) - PARSER_STREAM (parser) = LS_TOKEN_STOKEN (token).ptr; + unexpected_linespec_error (parser); + else if (token.type == LSTOKEN_KEYWORD) + { + /* Setup the completion word past the keyword. Lexing never + advances past a keyword automatically, so skip it + manually. */ + parser->completion_word + = skip_spaces (skip_to_space (PARSER_STREAM (parser))); + parser->complete_what = linespec_complete_what::EXPRESSION; + } /* Convert the data in PARSER_RESULT to SALs. */ - values = convert_linespec_to_sals (PARSER_STATE (parser), + if (parser->completion_tracker == NULL) + return convert_linespec_to_sals (PARSER_STATE (parser), PARSER_RESULT (parser)); - return values; + return {}; } @@ -2366,6 +2727,7 @@ parse_linespec (linespec_parser *parser, const char *arg) static void linespec_state_constructor (struct linespec_state *self, int flags, const struct language_defn *language, + struct program_space *search_pspace, struct symtab *default_symtab, int default_line, struct linespec_result *canonical) @@ -2374,6 +2736,7 @@ linespec_state_constructor (struct linespec_state *self, self->language = language; self->funfirstline = (flags & DECODE_LINE_FUNFIRSTLINE) ? 1 : 0; self->list_mode = (flags & DECODE_LINE_LIST_MODE) ? 1 : 0; + self->search_pspace = search_pspace; self->default_symtab = default_symtab; self->default_line = default_line; self->canonical = canonical; @@ -2388,6 +2751,7 @@ linespec_state_constructor (struct linespec_state *self, static void linespec_parser_new (linespec_parser *parser, int flags, const struct language_defn *language, + struct program_space *search_pspace, struct symtab *default_symtab, int default_line, struct linespec_result *canonical) @@ -2395,8 +2759,11 @@ linespec_parser_new (linespec_parser *parser, memset (parser, 0, sizeof (linespec_parser)); parser->lexer.current.type = LSTOKEN_CONSUMED; memset (PARSER_RESULT (parser), 0, sizeof (struct linespec)); + PARSER_EXPLICIT (parser)->func_name_match_type + = symbol_name_match_type::WILD; PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN; linespec_state_constructor (PARSER_STATE (parser), flags, language, + search_pspace, default_symtab, default_line, canonical); } @@ -2440,7 +2807,7 @@ linespec_parser_delete (void *arg) /* See description in linespec.h. */ void -linespec_lex_to_end (char **stringp) +linespec_lex_to_end (const char **stringp) { linespec_parser parser; struct cleanup *cleanup; @@ -2450,7 +2817,7 @@ linespec_lex_to_end (char **stringp) if (stringp == NULL || *stringp == NULL) return; - linespec_parser_new (&parser, 0, current_language, NULL, 0, NULL); + linespec_parser_new (&parser, 0, current_language, NULL, NULL, 0, NULL); cleanup = make_cleanup (linespec_parser_delete, &parser); parser.lexer.saved_arg = *stringp; PARSER_STREAM (&parser) = orig = *stringp; @@ -2470,14 +2837,361 @@ linespec_lex_to_end (char **stringp) do_cleanups (cleanup); } +/* See linespec.h. */ + +void +linespec_complete_function (completion_tracker &tracker, + const char *function, + symbol_name_match_type func_match_type, + const char *source_filename) +{ + complete_symbol_mode mode = complete_symbol_mode::LINESPEC; + + if (source_filename != NULL) + { + collect_file_symbol_completion_matches (tracker, mode, func_match_type, + function, function, source_filename); + } + else + { + collect_symbol_completion_matches (tracker, mode, func_match_type, + function, function); + + } +} + +/* Helper for complete_linespec to simplify it. SOURCE_FILENAME is + only meaningful if COMPONENT is FUNCTION. */ + +static void +complete_linespec_component (linespec_parser *parser, + completion_tracker &tracker, + const char *text, + linespec_complete_what component, + const char *source_filename) +{ + if (component == linespec_complete_what::KEYWORD) + { + complete_on_enum (tracker, linespec_keywords, text, text); + } + else if (component == linespec_complete_what::EXPRESSION) + { + const char *word + = advance_to_expression_complete_word_point (tracker, text); + complete_expression (tracker, text, word); + } + else if (component == linespec_complete_what::FUNCTION) + { + completion_list fn_list; + + symbol_name_match_type match_type + = PARSER_EXPLICIT (parser)->func_name_match_type; + linespec_complete_function (tracker, text, match_type, source_filename); + if (source_filename == NULL) + { + /* Haven't seen a source component, like in "b + file.c:function[TAB]". Maybe this wasn't a function, but + a filename instead, like "b file.[TAB]". */ + fn_list = complete_source_filenames (text); + } + + /* If we only have a single filename completion, append a ':' for + the user, since that's the only thing that can usefully follow + the filename. */ + if (fn_list.size () == 1 && !tracker.have_completions ()) + { + char *fn = fn_list[0].release (); + + /* If we also need to append a quote char, it needs to be + appended before the ':'. Append it now, and make ':' the + new "quote" char. */ + if (tracker.quote_char ()) + { + char quote_char_str[2] = { tracker.quote_char () }; + + fn = reconcat (fn, fn, quote_char_str, (char *) NULL); + tracker.set_quote_char (':'); + } + else + fn = reconcat (fn, fn, ":", (char *) NULL); + fn_list[0].reset (fn); + + /* Tell readline to skip appending a space. */ + tracker.set_suppress_append_ws (true); + } + tracker.add_completions (std::move (fn_list)); + } +} + +/* Helper for linespec_complete_label. Find labels that match + LABEL_NAME in the function symbols listed in the PARSER, and add + them to the tracker. */ + +static void +complete_label (completion_tracker &tracker, + linespec_parser *parser, + const char *label_name) +{ + VEC (symbolp) *label_function_symbols = NULL; + VEC (symbolp) *labels + = find_label_symbols (PARSER_STATE (parser), + PARSER_RESULT (parser)->function_symbols, + &label_function_symbols, + label_name, true); + + symbol *label; + for (int ix = 0; + VEC_iterate (symbolp, labels, ix, label); ++ix) + { + char *match = xstrdup (SYMBOL_SEARCH_NAME (label)); + tracker.add_completion (gdb::unique_xmalloc_ptr (match)); + } + VEC_free (symbolp, labels); +} + +/* See linespec.h. */ + +void +linespec_complete_label (completion_tracker &tracker, + const struct language_defn *language, + const char *source_filename, + const char *function_name, + symbol_name_match_type func_name_match_type, + const char *label_name) +{ + linespec_parser parser; + struct cleanup *cleanup; + + linespec_parser_new (&parser, 0, language, NULL, NULL, 0, NULL); + cleanup = make_cleanup (linespec_parser_delete, &parser); + + line_offset unknown_offset = { 0, LINE_OFFSET_UNKNOWN }; + + TRY + { + convert_explicit_location_to_linespec (PARSER_STATE (&parser), + PARSER_RESULT (&parser), + source_filename, + function_name, + func_name_match_type, + NULL, unknown_offset); + } + CATCH (ex, RETURN_MASK_ERROR) + { + do_cleanups (cleanup); + return; + } + END_CATCH + + complete_label (tracker, &parser, label_name); + + do_cleanups (cleanup); +} + +/* See description in linespec.h. */ + +void +linespec_complete (completion_tracker &tracker, const char *text, + symbol_name_match_type match_type) +{ + linespec_parser parser; + struct cleanup *cleanup; + const char *orig = text; + + linespec_parser_new (&parser, 0, current_language, NULL, NULL, 0, NULL); + cleanup = make_cleanup (linespec_parser_delete, &parser); + parser.lexer.saved_arg = text; + PARSER_EXPLICIT (&parser)->func_name_match_type = match_type; + PARSER_STREAM (&parser) = text; + + parser.completion_tracker = &tracker; + PARSER_STATE (&parser)->is_linespec = 1; + + /* Parse as much as possible. parser.completion_word will hold + furthest completion point we managed to parse to. */ + TRY + { + parse_linespec (&parser, text, match_type); + } + CATCH (except, RETURN_MASK_ERROR) + { + } + END_CATCH + + if (parser.completion_quote_char != '\0' + && parser.completion_quote_end != NULL + && parser.completion_quote_end[1] == '\0') + { + /* If completing a quoted string with the cursor right at + terminating quote char, complete the completion word without + interpretation, so that readline advances the cursor one + whitespace past the quote, even if there's no match. This + makes these cases behave the same: + + before: "b function()" + after: "b function() " + + before: "b 'function()'" + after: "b 'function()' " + + and trusts the user in this case: + + before: "b 'not_loaded_function_yet()'" + after: "b 'not_loaded_function_yet()' " + */ + parser.complete_what = linespec_complete_what::NOTHING; + parser.completion_quote_char = '\0'; + + gdb::unique_xmalloc_ptr text_copy + (xstrdup (parser.completion_word)); + tracker.add_completion (std::move (text_copy)); + } + + tracker.set_quote_char (parser.completion_quote_char); + + if (parser.complete_what == linespec_complete_what::LABEL) + { + parser.complete_what = linespec_complete_what::NOTHING; + + const char *func_name = PARSER_EXPLICIT (&parser)->function_name; + + VEC (symbolp) *function_symbols; + VEC (bound_minimal_symbol_d) *minimal_symbols; + find_linespec_symbols (PARSER_STATE (&parser), + PARSER_RESULT (&parser)->file_symtabs, + func_name, match_type, + &function_symbols, &minimal_symbols); + + PARSER_RESULT (&parser)->function_symbols = function_symbols; + PARSER_RESULT (&parser)->minimal_symbols = minimal_symbols; + + complete_label (tracker, &parser, parser.completion_word); + } + else if (parser.complete_what == linespec_complete_what::FUNCTION) + { + /* While parsing/lexing, we didn't know whether the completion + word completes to a unique function/source name already or + not. + + E.g.: + "b function() " + may need to complete either to: + "b function() const" + or to: + "b function() if/thread/task" + + Or, this: + "b foo t" + may need to complete either to: + "b foo template_fun()" + with "foo" being the template function's return type, or to: + "b foo thread/task" + + Or, this: + "b file" + may need to complete either to a source file name: + "b file.c" + or this, also a filename, but a unique completion: + "b file.c:" + or to a function name: + "b file_function" + + Address that by completing assuming source or function, and + seeing if we find a completion that matches exactly the + completion word. If so, then it must be a function (see note + below) and we advance the completion word to the end of input + and switch to KEYWORD completion mode. + + Note: if we find a unique completion for a source filename, + then it won't match the completion word, because the LCD will + contain a trailing ':'. And if we're completing at or after + the ':', then complete_linespec_component won't try to + complete on source filenames. */ + + const char *word = parser.completion_word; + + complete_linespec_component (&parser, tracker, + parser.completion_word, + linespec_complete_what::FUNCTION, + PARSER_EXPLICIT (&parser)->source_filename); + + parser.complete_what = linespec_complete_what::NOTHING; + + if (tracker.quote_char ()) + { + /* The function/file name was not close-quoted, so this + can't be a keyword. Note: complete_linespec_component + may have swapped the original quote char for ':' when we + get here, but that still indicates the same. */ + } + else if (!tracker.have_completions ()) + { + size_t key_start; + size_t wordlen = strlen (parser.completion_word); + + key_start + = string_find_incomplete_keyword_at_end (linespec_keywords, + parser.completion_word, + wordlen); + + if (key_start != -1 + || (wordlen > 0 + && parser.completion_word[wordlen - 1] == ' ')) + { + parser.completion_word += key_start; + parser.complete_what = linespec_complete_what::KEYWORD; + } + } + else if (tracker.completes_to_completion_word (word)) + { + /* Skip the function and complete on keywords. */ + parser.completion_word += strlen (word); + parser.complete_what = linespec_complete_what::KEYWORD; + tracker.discard_completions (); + } + } + + tracker.advance_custom_word_point_by (parser.completion_word - orig); + + complete_linespec_component (&parser, tracker, + parser.completion_word, + parser.complete_what, + PARSER_EXPLICIT (&parser)->source_filename); + + /* If we're past the "filename:function:label:offset" linespec, and + didn't find any match, then assume the user might want to create + a pending breakpoint anyway and offer the keyword + completions. */ + if (!parser.completion_quote_char + && (parser.complete_what == linespec_complete_what::FUNCTION + || parser.complete_what == linespec_complete_what::LABEL + || parser.complete_what == linespec_complete_what::NOTHING) + && !tracker.have_completions ()) + { + const char *end + = parser.completion_word + strlen (parser.completion_word); + + if (end > orig && end[-1] == ' ') + { + tracker.advance_custom_word_point_by (end - parser.completion_word); + + complete_linespec_component (&parser, tracker, end, + linespec_complete_what::KEYWORD, + NULL); + } + } + + do_cleanups (cleanup); +} + /* A helper function for decode_line_full and decode_line_1 to - turn LOCATION into symtabs_and_lines. */ + turn LOCATION into std::vector. */ -static struct symtabs_and_lines +static std::vector event_location_to_sals (linespec_parser *parser, const struct event_location *location) { - struct symtabs_and_lines result = {NULL, 0}; + std::vector result; switch (event_location_type (location)) { @@ -2486,7 +3200,9 @@ event_location_to_sals (linespec_parser *parser, PARSER_STATE (parser)->is_linespec = 1; TRY { - result = parse_linespec (parser, get_linespec_location (location)); + const linespec_location *ls = get_linespec_location (location); + result = parse_linespec (parser, + ls->spec_string, ls->match_type); } CATCH (except, RETURN_MASK_ERROR) { @@ -2497,9 +3213,27 @@ event_location_to_sals (linespec_parser *parser, break; case ADDRESS_LOCATION: - result - = convert_address_location_to_sals (PARSER_STATE (parser), - get_address_location (location)); + { + const char *addr_string = get_address_string_location (location); + CORE_ADDR addr = get_address_location (location); + + if (addr_string != NULL) + { + char *expr = xstrdup (addr_string); + const char *const_expr = expr; + struct cleanup *cleanup = make_cleanup (xfree, expr); + + addr = linespec_expression_to_pc (&const_expr); + if (PARSER_STATE (parser)->canonical != NULL) + PARSER_STATE (parser)->canonical->location + = copy_event_location (location); + + do_cleanups (cleanup); + } + + result = convert_address_location_to_sals (PARSER_STATE (parser), + addr); + } break; case EXPLICIT_LOCATION: @@ -2529,12 +3263,12 @@ event_location_to_sals (linespec_parser *parser, void decode_line_full (const struct event_location *location, int flags, + struct program_space *search_pspace, struct symtab *default_symtab, int default_line, struct linespec_result *canonical, const char *select_mode, const char *filter) { - struct symtabs_and_lines result; struct cleanup *cleanups; VEC (const_char_ptr) *filters = NULL; linespec_parser parser; @@ -2549,24 +3283,27 @@ decode_line_full (const struct event_location *location, int flags, || select_mode == multiple_symbols_cancel); gdb_assert ((flags & DECODE_LINE_LIST_MODE) == 0); - linespec_parser_new (&parser, flags, current_language, default_symtab, + linespec_parser_new (&parser, flags, current_language, + search_pspace, default_symtab, default_line, canonical); cleanups = make_cleanup (linespec_parser_delete, &parser); - save_current_program_space (); - result = event_location_to_sals (&parser, location); + scoped_restore_current_program_space restore_pspace; + + std::vector result = event_location_to_sals (&parser, + location); state = PARSER_STATE (&parser); - gdb_assert (result.nelts == 1 || canonical->pre_expanded); + gdb_assert (result.size () == 1 || canonical->pre_expanded); canonical->pre_expanded = 1; /* Arrange for allocated canonical names to be freed. */ - if (result.nelts > 0) + if (!result.empty ()) { int i; make_cleanup (xfree, state->canonical_names); - for (i = 0; i < result.nelts; ++i) + for (i = 0; i < result.size (); ++i) { gdb_assert (state->canonical_names[i].suffix != NULL); make_cleanup (xfree, state->canonical_names[i].suffix); @@ -2575,7 +3312,7 @@ decode_line_full (const struct event_location *location, int flags, if (select_mode == NULL) { - if (ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ()))) + if (interp_ui_out (top_level_interpreter ())->is_mi_like_p ()) select_mode = multiple_symbols_all; else select_mode = multiple_symbols_select_mode (); @@ -2600,21 +3337,24 @@ decode_line_full (const struct event_location *location, int flags, /* See linespec.h. */ -struct symtabs_and_lines +std::vector decode_line_1 (const struct event_location *location, int flags, + struct program_space *search_pspace, struct symtab *default_symtab, int default_line) { - struct symtabs_and_lines result; linespec_parser parser; struct cleanup *cleanups; - linespec_parser_new (&parser, flags, current_language, default_symtab, + linespec_parser_new (&parser, flags, current_language, + search_pspace, default_symtab, default_line, NULL); cleanups = make_cleanup (linespec_parser_delete, &parser); - save_current_program_space (); - result = event_location_to_sals (&parser, location); + scoped_restore_current_program_space restore_pspace; + + std::vector result = event_location_to_sals (&parser, + location); do_cleanups (cleanups); return result; @@ -2622,58 +3362,48 @@ decode_line_1 (const struct event_location *location, int flags, /* See linespec.h. */ -struct symtabs_and_lines -decode_line_with_current_source (char *string, int flags) +std::vector +decode_line_with_current_source (const char *string, int flags) { - struct symtabs_and_lines sals; - struct symtab_and_line cursal; - struct event_location *location; - struct cleanup *cleanup; - if (string == 0) error (_("Empty line specification.")); /* We use whatever is set as the current source line. We do not try and get a default source symtab+line or it will recursively call us! */ - cursal = get_current_source_symtab_and_line (); + symtab_and_line cursal = get_current_source_symtab_and_line (); - location = string_to_event_location (&string, current_language); - cleanup = make_cleanup_delete_event_location (location); - sals = decode_line_1 (location, flags, - cursal.symtab, cursal.line); + event_location_up location = string_to_event_location (&string, + current_language); + std::vector sals + = decode_line_1 (location.get (), flags, NULL, cursal.symtab, cursal.line); if (*string) error (_("Junk at end of line specification: %s"), string); - do_cleanups (cleanup); return sals; } /* See linespec.h. */ -struct symtabs_and_lines -decode_line_with_last_displayed (char *string, int flags) +std::vector +decode_line_with_last_displayed (const char *string, int flags) { - struct symtabs_and_lines sals; - struct event_location *location; - struct cleanup *cleanup; - if (string == 0) error (_("Empty line specification.")); - location = string_to_event_location (&string, current_language); - cleanup = make_cleanup_delete_event_location (location); - if (last_displayed_sal_is_valid ()) - sals = decode_line_1 (location, flags, - get_last_displayed_symtab (), - get_last_displayed_line ()); - else - sals = decode_line_1 (location, flags, (struct symtab *) NULL, 0); + event_location_up location = string_to_event_location (&string, + current_language); + std::vector sals + = (last_displayed_sal_is_valid () + ? decode_line_1 (location.get (), flags, NULL, + get_last_displayed_symtab (), + get_last_displayed_line ()) + : decode_line_1 (location.get (), flags, NULL, + (struct symtab *) NULL, 0)); if (*string) error (_("Junk at end of line specification: %s"), string); - do_cleanups (cleanup); return sals; } @@ -2725,12 +3455,11 @@ linespec_expression_to_pc (const char **exp_ptr) than one method that could represent the selector, then use some of the existing C++ code to let the user choose one. */ -static struct symtabs_and_lines +static std::vector decode_objc (struct linespec_state *self, linespec_p ls, const char *arg) { struct collect_info info; VEC (const_char_ptr) *symbol_names = NULL; - struct symtabs_and_lines values; const char *new_argptr; struct cleanup *cleanup = make_cleanup (VEC_cleanup (const_char_ptr), &symbol_names); @@ -2741,24 +3470,24 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg) make_cleanup (VEC_cleanup (symtab_ptr), &info.file_symtabs); info.result.symbols = NULL; info.result.minimal_symbols = NULL; - values.nelts = 0; - values.sals = NULL; new_argptr = find_imps (arg, &symbol_names); if (VEC_empty (const_char_ptr, symbol_names)) { do_cleanups (cleanup); - return values; + return {}; } - add_all_symbol_names_from_pspace (&info, NULL, symbol_names); + add_all_symbol_names_from_pspace (&info, NULL, symbol_names, + FUNCTIONS_DOMAIN); + std::vector values; if (!VEC_empty (symbolp, info.result.symbols) || !VEC_empty (bound_minimal_symbol_d, info.result.minimal_symbols)) { char *saved_arg; - saved_arg = alloca (new_argptr - arg + 1); + saved_arg = (char *) alloca (new_argptr - arg + 1); memcpy (saved_arg, arg, new_argptr - arg); saved_arg[new_argptr - arg] = '\0'; @@ -2769,20 +3498,23 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg) if (self->canonical) { - char *str; + std::string holder; + const char *str; self->canonical->pre_expanded = 1; if (ls->explicit_loc.source_filename) { - str = xstrprintf ("%s:%s", - ls->explicit_loc.source_filename, saved_arg); + holder = string_printf ("%s:%s", + ls->explicit_loc.source_filename, + saved_arg); + str = holder.c_str (); } else - str = xstrdup (saved_arg); + str = saved_arg; - make_cleanup (xfree, str); - self->canonical->location = new_linespec_location (&str); + self->canonical->location + = new_linespec_location (&str, symbol_name_match_type::FULL); } } @@ -2791,49 +3523,76 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg) return values; } -/* An instance of this type is used when collecting prefix symbols for - decode_compound. */ +namespace { -struct decode_compound_collector +/* A function object that serves as symbol_found_callback_ftype + callback for iterate_over_symbols. This is used by + lookup_prefix_sym to collect type symbols. */ +class decode_compound_collector { - /* The result vector. */ - VEC (symbolp) *symbols; +public: + decode_compound_collector () + : m_symbols (NULL) + { + m_unique_syms = htab_create_alloc (1, htab_hash_pointer, + htab_eq_pointer, NULL, + xcalloc, xfree); + } + ~decode_compound_collector () + { + if (m_unique_syms != NULL) + htab_delete (m_unique_syms); + } + + /* Releases ownership of the collected symbols and returns them. */ + VEC (symbolp) *release_symbols () + { + VEC (symbolp) *res = m_symbols; + m_symbols = NULL; + return res; + } + + /* Callable as a symbol_found_callback_ftype callback. */ + bool operator () (symbol *sym); + +private: /* A hash table of all symbols we found. We use this to avoid adding any symbol more than once. */ - htab_t unique_syms; -}; + htab_t m_unique_syms; -/* A callback for iterate_over_symbols that is used by - lookup_prefix_sym to collect type symbols. */ + /* The result vector. */ + VEC (symbolp) *m_symbols; +}; -static int -collect_one_symbol (struct symbol *sym, void *d) +bool +decode_compound_collector::operator () (symbol *sym) { - struct decode_compound_collector *collector = d; void **slot; struct type *t; if (SYMBOL_CLASS (sym) != LOC_TYPEDEF) - return 1; /* Continue iterating. */ + return true; /* Continue iterating. */ t = SYMBOL_TYPE (sym); t = check_typedef (t); if (TYPE_CODE (t) != TYPE_CODE_STRUCT && TYPE_CODE (t) != TYPE_CODE_UNION && TYPE_CODE (t) != TYPE_CODE_NAMESPACE) - return 1; /* Continue iterating. */ + return true; /* Continue iterating. */ - slot = htab_find_slot (collector->unique_syms, sym, INSERT); + slot = htab_find_slot (m_unique_syms, sym, INSERT); if (!*slot) { *slot = sym; - VEC_safe_push (symbolp, collector->symbols, sym); + VEC_safe_push (symbolp, m_symbols, sym); } - return 1; /* Continue iterating. */ + return true; /* Continue iterating. */ } +} // namespace + /* Return any symbols corresponding to CLASS_NAME in FILE_SYMTABS. */ static VEC (symbolp) * @@ -2842,28 +3601,20 @@ lookup_prefix_sym (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, { int ix; struct symtab *elt; - struct decode_compound_collector collector; - struct cleanup *outer; - struct cleanup *cleanup; - - collector.symbols = NULL; - outer = make_cleanup (VEC_cleanup (symbolp), &collector.symbols); + decode_compound_collector collector; - collector.unique_syms = htab_create_alloc (1, htab_hash_pointer, - htab_eq_pointer, NULL, - xcalloc, xfree); - cleanup = make_cleanup_htab_delete (collector.unique_syms); + lookup_name_info lookup_name (class_name, symbol_name_match_type::FULL); for (ix = 0; VEC_iterate (symtab_ptr, file_symtabs, ix, elt); ++ix) { if (elt == NULL) { - iterate_over_all_matching_symtabs (state, class_name, STRUCT_DOMAIN, - collect_one_symbol, &collector, - NULL, 0); - iterate_over_all_matching_symtabs (state, class_name, VAR_DOMAIN, - collect_one_symbol, &collector, - NULL, 0); + iterate_over_all_matching_symtabs (state, lookup_name, + STRUCT_DOMAIN, ALL_DOMAIN, + NULL, false, collector); + iterate_over_all_matching_symtabs (state, lookup_name, + VAR_DOMAIN, ALL_DOMAIN, + NULL, false, collector); } else { @@ -2871,16 +3622,12 @@ lookup_prefix_sym (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, been filtered out earlier. */ gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup); set_current_program_space (SYMTAB_PSPACE (elt)); - iterate_over_file_blocks (elt, class_name, STRUCT_DOMAIN, - collect_one_symbol, &collector); - iterate_over_file_blocks (elt, class_name, VAR_DOMAIN, - collect_one_symbol, &collector); + iterate_over_file_blocks (elt, lookup_name, STRUCT_DOMAIN, collector); + iterate_over_file_blocks (elt, lookup_name, VAR_DOMAIN, collector); } } - do_cleanups (cleanup); - discard_cleanups (outer); - return collector.symbols; + return collector.release_symbols (); } /* A qsort comparison function for symbols. The resulting order does @@ -2890,8 +3637,8 @@ lookup_prefix_sym (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, static int compare_symbols (const void *a, const void *b) { - struct symbol * const *sa = a; - struct symbol * const *sb = b; + struct symbol * const *sa = (struct symbol * const*) a; + struct symbol * const *sb = (struct symbol * const*) b; uintptr_t uia, uib; uia = (uintptr_t) SYMTAB_PSPACE (symbol_symtab (*sa)); @@ -2918,8 +3665,10 @@ compare_symbols (const void *a, const void *b) static int compare_msymbols (const void *a, const void *b) { - const struct bound_minimal_symbol *sa = a; - const struct bound_minimal_symbol *sb = b; + const struct bound_minimal_symbol *sa + = (const struct bound_minimal_symbol *) a; + const struct bound_minimal_symbol *sb + = (const struct bound_minimal_symbol *) b; uintptr_t uia, uib; uia = (uintptr_t) sa->objfile->pspace; @@ -2949,18 +3698,21 @@ compare_msymbols (const void *a, const void *b) static void add_all_symbol_names_from_pspace (struct collect_info *info, struct program_space *pspace, - VEC (const_char_ptr) *names) + VEC (const_char_ptr) *names, + enum search_domain search_domain) { int ix; const char *iter; for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix) - add_matching_symbols_to_info (iter, info, pspace); + add_matching_symbols_to_info (iter, + symbol_name_match_type::FULL, + search_domain, info, pspace); } static void find_superclass_methods (VEC (typep) *superclasses, - const char *name, + const char *name, enum language name_lang, VEC (const_char_ptr) **result_names) { int old_len = VEC_length (const_char_ptr, *result_names); @@ -2976,7 +3728,7 @@ find_superclass_methods (VEC (typep) *superclasses, make_cleanup (VEC_cleanup (typep), &new_supers); for (ix = 0; VEC_iterate (typep, iter_classes, ix, t); ++ix) - find_methods (t, name, result_names, &new_supers); + find_methods (t, name_lang, name, result_names, &new_supers); if (VEC_length (const_char_ptr, *result_names) != old_len || VEC_empty (typep, new_supers)) @@ -3043,7 +3795,8 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, gdb_assert (!pspace->executing_startup); set_current_program_space (pspace); t = check_typedef (SYMBOL_TYPE (sym)); - find_methods (t, method_name, &result_names, &superclass_vec); + find_methods (t, SYMBOL_LANGUAGE (sym), + method_name, &result_names, &superclass_vec); /* Handle all items from a single program space at once; and be sure not to miss the last batch. */ @@ -3056,12 +3809,13 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, this program space, consider superclasses. */ if (VEC_length (const_char_ptr, result_names) == last_result_len) find_superclass_methods (superclass_vec, method_name, - &result_names); + SYMBOL_LANGUAGE (sym), &result_names); /* We have a list of candidate symbol names, so now we iterate over the symbol tables looking for all matches in this pspace. */ - add_all_symbol_names_from_pspace (&info, pspace, result_names); + add_all_symbol_names_from_pspace (&info, pspace, result_names, + FUNCTIONS_DOMAIN); VEC_truncate (typep, superclass_vec, 0); last_result_len = VEC_length (const_char_ptr, result_names); @@ -3084,71 +3838,106 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, -/* This object is used when collecting all matching symtabs. */ +namespace { + +/* This function object is a callback for iterate_over_symtabs, used + when collecting all matching symtabs. */ -struct symtab_collector +class symtab_collector { +public: + symtab_collector () + { + m_symtabs = NULL; + m_symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer, + NULL); + } + + ~symtab_collector () + { + if (m_symtab_table != NULL) + htab_delete (m_symtab_table); + } + + /* Callable as a symbol_found_callback_ftype callback. */ + bool operator () (symtab *sym); + + /* Releases ownership of the collected symtabs and returns them. */ + VEC (symtab_ptr) *release_symtabs () + { + VEC (symtab_ptr) *res = m_symtabs; + m_symtabs = NULL; + return res; + } + +private: /* The result vector of symtabs. */ - VEC (symtab_ptr) *symtabs; + VEC (symtab_ptr) *m_symtabs; /* This is used to ensure the symtabs are unique. */ - htab_t symtab_table; + htab_t m_symtab_table; }; -/* Callback for iterate_over_symtabs. */ - -static int -add_symtabs_to_list (struct symtab *symtab, void *d) +bool +symtab_collector::operator () (struct symtab *symtab) { - struct symtab_collector *data = d; void **slot; - slot = htab_find_slot (data->symtab_table, symtab, INSERT); + slot = htab_find_slot (m_symtab_table, symtab, INSERT); if (!*slot) { *slot = symtab; - VEC_safe_push (symtab_ptr, data->symtabs, symtab); + VEC_safe_push (symtab_ptr, m_symtabs, symtab); } - return 0; + return false; } -/* Given a file name, return a VEC of all matching symtabs. */ +} // namespace + +/* Given a file name, return a VEC of all matching symtabs. If + SEARCH_PSPACE is not NULL, the search is restricted to just that + program space. */ static VEC (symtab_ptr) * -collect_symtabs_from_filename (const char *file) +collect_symtabs_from_filename (const char *file, + struct program_space *search_pspace) { - struct symtab_collector collector; - struct cleanup *cleanups; - struct program_space *pspace; - - collector.symtabs = NULL; - collector.symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer, - NULL); - cleanups = make_cleanup_htab_delete (collector.symtab_table); + symtab_collector collector; /* Find that file's data. */ - ALL_PSPACES (pspace) - { - if (pspace->executing_startup) - continue; + if (search_pspace == NULL) + { + struct program_space *pspace; - set_current_program_space (pspace); - iterate_over_symtabs (file, add_symtabs_to_list, &collector); - } + ALL_PSPACES (pspace) + { + if (pspace->executing_startup) + continue; - do_cleanups (cleanups); - return collector.symtabs; + set_current_program_space (pspace); + iterate_over_symtabs (file, collector); + } + } + else + { + set_current_program_space (search_pspace); + iterate_over_symtabs (file, collector); + } + + return collector.release_symtabs (); } -/* Return all the symtabs associated to the FILENAME. */ +/* Return all the symtabs associated to the FILENAME. If SEARCH_PSPACE is + not NULL, the search is restricted to just that program space. */ static VEC (symtab_ptr) * -symtabs_from_filename (const char *filename) +symtabs_from_filename (const char *filename, + struct program_space *search_pspace) { VEC (symtab_ptr) *result; - result = collect_symtabs_from_filename (filename); + result = collect_symtabs_from_filename (filename, search_pspace); if (VEC_empty (symtab_ptr, result)) { @@ -3169,6 +3958,7 @@ symtabs_from_filename (const char *filename) static void find_function_symbols (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, const char *name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms) { @@ -3185,9 +3975,11 @@ find_function_symbols (struct linespec_state *state, /* Try NAME as an Objective-C selector. */ find_imps (name, &symbol_names); if (!VEC_empty (const_char_ptr, symbol_names)) - add_all_symbol_names_from_pspace (&info, NULL, symbol_names); + add_all_symbol_names_from_pspace (&info, state->search_pspace, + symbol_names, FUNCTIONS_DOMAIN); else - add_matching_symbols_to_info (name, &info, NULL); + add_matching_symbols_to_info (name, name_match_type, FUNCTIONS_DOMAIN, + &info, state->search_pspace); do_cleanups (cleanup); @@ -3214,30 +4006,14 @@ find_function_symbols (struct linespec_state *state, static void find_linespec_symbols (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, - const char *name, + const char *lookup_name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms) { - struct cleanup *cleanup; - char *canon; - const char *lookup_name; - - cleanup = demangle_for_lookup (name, state->language->la_language, - &lookup_name); - if (state->language->la_language == language_ada) - { - /* In Ada, the symbol lookups are performed using the encoded - name rather than the demangled name. */ - lookup_name = ada_name_for_lookup (name); - make_cleanup (xfree, (void *) lookup_name); - } - - canon = cp_canonicalize_string_no_typedefs (lookup_name); - if (canon != NULL) - { - lookup_name = canon; - make_cleanup (xfree, canon); - } + std::string canon = cp_canonicalize_string_no_typedefs (lookup_name); + if (!canon.empty ()) + lookup_name = canon.c_str (); /* It's important to not call expand_symtabs_matching unnecessarily as it can really slow things down (by unnecessarily expanding @@ -3249,6 +4025,7 @@ find_linespec_symbols (struct linespec_state *state, 2) break class::method where method is in class (and not a baseclass) */ find_function_symbols (state, file_symtabs, lookup_name, + name_match_type, symbols, minsyms); /* If we were unable to locate a symbol of the same name, try dividing @@ -3257,7 +4034,7 @@ find_linespec_symbols (struct linespec_state *state, if (VEC_empty (symbolp, *symbols) && VEC_empty (bound_minimal_symbol_d, *minsyms)) { - char *klass, *method; + std::string klass, method; const char *last, *p, *scope_op; VEC (symbolp) *classes; @@ -3265,12 +4042,6 @@ find_linespec_symbols (struct linespec_state *state, name into namespaces${SCOPE_OPERATOR}class_name and method_name. */ scope_op = "::"; p = find_toplevel_string (lookup_name, scope_op); - if (p == NULL) - { - /* No C++ scope operator. Try Java. */ - scope_op = "."; - p = find_toplevel_string (lookup_name, scope_op); - } last = NULL; while (p != NULL) @@ -3283,35 +4054,29 @@ find_linespec_symbols (struct linespec_state *state, we already attempted to lookup the entire name as a symbol and failed. */ if (last == NULL) - { - do_cleanups (cleanup); - return; - } + return; /* LOOKUP_NAME points to the class name. LAST points to the method name. */ - klass = xmalloc ((last - lookup_name + 1) * sizeof (char)); - make_cleanup (xfree, klass); - strncpy (klass, lookup_name, last - lookup_name); - klass[last - lookup_name] = '\0'; + klass = std::string (lookup_name, last - lookup_name); /* Skip past the scope operator. */ last += strlen (scope_op); - method = xmalloc ((strlen (last) + 1) * sizeof (char)); - make_cleanup (xfree, method); - strcpy (method, last); + method = last; /* Find a list of classes named KLASS. */ - classes = lookup_prefix_sym (state, file_symtabs, klass); - make_cleanup (VEC_cleanup (symbolp), &classes); + classes = lookup_prefix_sym (state, file_symtabs, klass.c_str ()); + struct cleanup *old_chain + = make_cleanup (VEC_cleanup (symbolp), &classes); if (!VEC_empty (symbolp, classes)) { /* Now locate a list of suitable methods named METHOD. */ TRY { - find_method (state, file_symtabs, klass, method, classes, - symbols, minsyms); + find_method (state, file_symtabs, + klass.c_str (), method.c_str (), + classes, symbols, minsyms); } /* If successful, we're done. If NOT_FOUND_ERROR @@ -3323,22 +4088,71 @@ find_linespec_symbols (struct linespec_state *state, } END_CATCH } + + do_cleanups (old_chain); + } +} + +/* Helper for find_label_symbols. Find all labels that match name + NAME in BLOCK. Return all labels that match in FUNCTION_SYMBOLS. + Return the actual function symbol in which the label was found in + LABEL_FUNC_RET. If COMPLETION_MODE is true, then NAME is + interpreted as a label name prefix. Otherwise, only a label named + exactly NAME match. */ + +static void +find_label_symbols_in_block (const struct block *block, + const char *name, struct symbol *fn_sym, + bool completion_mode, + VEC (symbolp) **result, + VEC (symbolp) **label_funcs_ret) +{ + if (completion_mode) + { + struct block_iterator iter; + struct symbol *sym; + size_t name_len = strlen (name); + + int (*cmp) (const char *, const char *, size_t); + cmp = case_sensitivity == case_sensitive_on ? strncmp : strncasecmp; + + ALL_BLOCK_SYMBOLS (block, iter, sym) + { + if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), + SYMBOL_DOMAIN (sym), LABEL_DOMAIN) + && cmp (SYMBOL_SEARCH_NAME (sym), name, name_len) == 0) + { + VEC_safe_push (symbolp, *result, sym); + VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); + } + } } + else + { + struct symbol *sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol; - do_cleanups (cleanup); + if (sym != NULL) + { + VEC_safe_push (symbolp, *result, sym); + VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); + } + } } -/* Return all labels named NAME in FUNCTION_SYMBOLS. Return the - actual function symbol in which the label was found in LABEL_FUNC_RET. */ +/* Return all labels that match name NAME in FUNCTION_SYMBOLS. Return + the actual function symbol in which the label was found in + LABEL_FUNC_RET. If COMPLETION_MODE is true, then NAME is + interpreted as a label name prefix. Otherwise, only labels named + exactly NAME match. */ static VEC (symbolp) * find_label_symbols (struct linespec_state *self, VEC (symbolp) *function_symbols, - VEC (symbolp) **label_funcs_ret, const char *name) + VEC (symbolp) **label_funcs_ret, const char *name, + bool completion_mode) { int ix; const struct block *block; - struct symbol *sym; struct symbol *fn_sym; VEC (symbolp) *result = NULL; @@ -3355,13 +4169,8 @@ find_label_symbols (struct linespec_state *self, return NULL; fn_sym = BLOCK_FUNCTION (block); - sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol; - - if (sym != NULL) - { - VEC_safe_push (symbolp, result, sym); - VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); - } + find_label_symbols_in_block (block, name, fn_sym, completion_mode, + &result, label_funcs_ret); } else { @@ -3370,13 +4179,9 @@ find_label_symbols (struct linespec_state *self, { set_current_program_space (SYMTAB_PSPACE (symbol_symtab (fn_sym))); block = SYMBOL_BLOCK_VALUE (fn_sym); - sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol; - if (sym != NULL) - { - VEC_safe_push (symbolp, result, sym); - VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); - } + find_label_symbols_in_block (block, name, fn_sym, completion_mode, + &result, label_funcs_ret); } } @@ -3387,10 +4192,9 @@ find_label_symbols (struct linespec_state *self, /* A helper for create_sals_line_offset that handles the 'list_mode' case. */ -static void +static std::vector decode_digits_list_mode (struct linespec_state *self, linespec_p ls, - struct symtabs_and_lines *values, struct symtab_and_line val) { int ix; @@ -3398,6 +4202,8 @@ decode_digits_list_mode (struct linespec_state *self, gdb_assert (self->list_mode); + std::vector values; + for (ix = 0; VEC_iterate (symtab_ptr, ls->file_symtabs, ix, elt); ++ix) { @@ -3414,28 +4220,28 @@ decode_digits_list_mode (struct linespec_state *self, val.pc = 0; val.explicit_line = 1; - add_sal_to_sals (self, values, &val, NULL, 0); + add_sal_to_sals (self, &values, &val, NULL, 0); } + + return values; } /* A helper for create_sals_line_offset that iterates over the symtabs, adding lines to the VEC. */ -static void +static std::vector decode_digits_ordinary (struct linespec_state *self, linespec_p ls, int line, - struct symtabs_and_lines *sals, struct linetable_entry **best_entry) { int ix; struct symtab *elt; + std::vector sals; for (ix = 0; VEC_iterate (symtab_ptr, ls->file_symtabs, ix, elt); ++ix) { - int i; - VEC (CORE_ADDR) *pcs; - CORE_ADDR pc; + std::vector pcs; /* The logic above should ensure this. */ gdb_assert (elt != NULL); @@ -3443,20 +4249,18 @@ decode_digits_ordinary (struct linespec_state *self, set_current_program_space (SYMTAB_PSPACE (elt)); pcs = find_pcs_for_symtab_line (elt, line, best_entry); - for (i = 0; VEC_iterate (CORE_ADDR, pcs, i, pc); ++i) + for (CORE_ADDR pc : pcs) { - struct symtab_and_line sal; - - init_sal (&sal); + symtab_and_line sal; sal.pspace = SYMTAB_PSPACE (elt); sal.symtab = elt; sal.line = line; sal.pc = pc; - add_sal_to_sals_basic (sals, &sal); + sals.push_back (std::move (sal)); } - - VEC_free (CORE_ADDR, pcs); } + + return sals; } @@ -3518,20 +4322,6 @@ linespec_parse_variable (struct linespec_state *self, const char *variable) } -/* A callback used to possibly add a symbol to the results. */ - -static int -collect_symbols (struct symbol *sym, void *data) -{ - struct collect_info *info = data; - - /* In list mode, add all matching symbols, regardless of class. - This allows the user to type "list a_global_variable". */ - if (SYMBOL_CLASS (sym) == LOC_BLOCK || info->state->list_mode) - VEC_safe_push (symbolp, info->result.symbols, sym); - return 1; /* Continue iterating. */ -} - /* We've found a minimal symbol MSYMBOL in OBJFILE to associate with our linespec; return the SAL in RESULT. This function should return SALs matching those from find_function_start_sal, otherwise false @@ -3540,68 +4330,44 @@ collect_symbols (struct symbol *sym, void *data) static void minsym_found (struct linespec_state *self, struct objfile *objfile, struct minimal_symbol *msymbol, - struct symtabs_and_lines *result) + std::vector *result) { - struct gdbarch *gdbarch = get_objfile_arch (objfile); - CORE_ADDR pc; struct symtab_and_line sal; - sal = find_pc_sect_line (MSYMBOL_VALUE_ADDRESS (objfile, msymbol), - (struct obj_section *) 0, 0); - sal.section = MSYMBOL_OBJ_SECTION (objfile, msymbol); + CORE_ADDR func_addr; + if (msymbol_is_function (objfile, msymbol, &func_addr)) + { + sal = find_pc_sect_line (func_addr, NULL, 0); - /* The minimal symbol might point to a function descriptor; - resolve it to the actual code address instead. */ - pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, ¤t_target); - if (pc != sal.pc) - sal = find_pc_sect_line (pc, NULL, 0); - - if (self->funfirstline) - { - if (sal.symtab != NULL - && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab)) - || SYMTAB_LANGUAGE (sal.symtab) == language_asm)) - { - /* If gdbarch_convert_from_func_ptr_addr does not apply then - sal.SECTION, sal.LINE&co. will stay correct from above. - If gdbarch_convert_from_func_ptr_addr applies then - sal.SECTION is cleared from above and sal.LINE&co. will - stay correct from the last find_pc_sect_line above. */ - sal.pc = MSYMBOL_VALUE_ADDRESS (objfile, msymbol); - sal.pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, - ¤t_target); - if (gdbarch_skip_entrypoint_p (gdbarch)) - sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc); + if (self->funfirstline) + { + if (sal.symtab != NULL + && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab)) + || SYMTAB_LANGUAGE (sal.symtab) == language_asm)) + { + struct gdbarch *gdbarch = get_objfile_arch (objfile); + + sal.pc = func_addr; + if (gdbarch_skip_entrypoint_p (gdbarch)) + sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc); + } + else + skip_prologue_sal (&sal); } - else - skip_prologue_sal (&sal); + } + else + { + sal.objfile = objfile; + sal.pc = MSYMBOL_VALUE_ADDRESS (objfile, msymbol); + sal.pspace = current_program_space; } + sal.section = MSYMBOL_OBJ_SECTION (objfile, msymbol); + if (maybe_add_address (self->addr_set, objfile->pspace, sal.pc)) add_sal_to_sals (self, result, &sal, MSYMBOL_NATURAL_NAME (msymbol), 0); } -/* A helper struct to pass some data through - iterate_over_minimal_symbols. */ - -struct collect_minsyms -{ - /* The objfile we're examining. */ - struct objfile *objfile; - - /* Only search the given symtab, or NULL to search for all symbols. */ - struct symtab *symtab; - - /* The funfirstline setting from the initial call. */ - int funfirstline; - - /* The list_mode setting from the initial call. */ - int list_mode; - - /* The resulting symbols. */ - VEC (bound_minimal_symbol_d) *msyms; -}; - /* A helper function to classify a minimal_symbol_type according to priority. */ @@ -3626,73 +4392,45 @@ classify_mtype (enum minimal_symbol_type t) } } -/* Callback for qsort that sorts symbols by priority. */ +/* Callback for std::sort that sorts symbols by priority. */ -static int -compare_msyms (const void *a, const void *b) +static bool +compare_msyms (const bound_minimal_symbol &a, const bound_minimal_symbol &b) { - const bound_minimal_symbol_d *moa = a; - const bound_minimal_symbol_d *mob = b; - enum minimal_symbol_type ta = MSYMBOL_TYPE (moa->minsym); - enum minimal_symbol_type tb = MSYMBOL_TYPE (mob->minsym); + enum minimal_symbol_type ta = MSYMBOL_TYPE (a.minsym); + enum minimal_symbol_type tb = MSYMBOL_TYPE (b.minsym); - return classify_mtype (ta) - classify_mtype (tb); + return classify_mtype (ta) < classify_mtype (tb); } -/* Callback for iterate_over_minimal_symbols that adds the symbol to - the result. */ +/* Helper for search_minsyms_for_name that adds the symbol to the + result. */ static void -add_minsym (struct minimal_symbol *minsym, void *d) +add_minsym (struct minimal_symbol *minsym, struct objfile *objfile, + struct symtab *symtab, int list_mode, + std::vector *msyms) { - struct collect_minsyms *info = d; - bound_minimal_symbol_d mo; - - mo.minsym = minsym; - mo.objfile = info->objfile; - - if (info->symtab != NULL) + if (symtab != NULL) { - CORE_ADDR pc; - struct symtab_and_line sal; - struct gdbarch *gdbarch = get_objfile_arch (info->objfile); - - sal = find_pc_sect_line (MSYMBOL_VALUE_ADDRESS (info->objfile, minsym), - NULL, 0); - sal.section = MSYMBOL_OBJ_SECTION (info->objfile, minsym); - pc - = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, ¤t_target); - if (pc != sal.pc) - sal = find_pc_sect_line (pc, NULL, 0); + /* We're looking for a label for which we don't have debug + info. */ + CORE_ADDR func_addr; + if (msymbol_is_function (objfile, minsym, &func_addr)) + { + symtab_and_line sal = find_pc_sect_line (func_addr, NULL, 0); - if (info->symtab != sal.symtab) - return; + if (symtab != sal.symtab) + return; + } } - /* Exclude data symbols when looking for breakpoint locations. */ - if (!info->list_mode) - switch (minsym->type) - { - case mst_slot_got_plt: - case mst_data: - case mst_bss: - case mst_abs: - case mst_file_data: - case mst_file_bss: - { - /* Make sure this minsym is not a function descriptor - before we decide to discard it. */ - struct gdbarch *gdbarch = get_objfile_arch (info->objfile); - CORE_ADDR addr = gdbarch_convert_from_func_ptr_addr - (gdbarch, BMSYMBOL_VALUE_ADDRESS (mo), - ¤t_target); - - if (addr == BMSYMBOL_VALUE_ADDRESS (mo)) - return; - } - } + /* Exclude data symbols when looking for breakpoint locations. */ + if (!list_mode && !msymbol_is_function (objfile, minsym)) + return; - VEC_safe_push (bound_minimal_symbol_d, info->msyms, &mo); + struct bound_minimal_symbol mo = {minsym, objfile}; + msyms->push_back (mo); } /* Search for minimal symbols called NAME. If SEARCH_PSPACE @@ -3703,19 +4441,12 @@ add_minsym (struct minimal_symbol *minsym, void *d) restrict results to the given SYMTAB. */ static void -search_minsyms_for_name (struct collect_info *info, const char *name, +search_minsyms_for_name (struct collect_info *info, + const lookup_name_info &name, struct program_space *search_pspace, struct symtab *symtab) { - struct collect_minsyms local; - struct cleanup *cleanup; - - memset (&local, 0, sizeof (local)); - local.funfirstline = info->state->funfirstline; - local.list_mode = info->state->list_mode; - local.symtab = symtab; - - cleanup = make_cleanup (VEC_cleanup (bound_minimal_symbol_d), &local.msyms); + std::vector minsyms; if (symtab == NULL) { @@ -3734,8 +4465,13 @@ search_minsyms_for_name (struct collect_info *info, const char *name, ALL_OBJFILES (objfile) { - local.objfile = objfile; - iterate_over_minimal_symbols (objfile, name, add_minsym, &local); + iterate_over_minimal_symbols (objfile, name, + [&] (struct minimal_symbol *msym) + { + add_minsym (msym, objfile, nullptr, + info->state->list_mode, + &minsyms); + }); } } } @@ -3744,42 +4480,36 @@ search_minsyms_for_name (struct collect_info *info, const char *name, if (search_pspace == NULL || SYMTAB_PSPACE (symtab) == search_pspace) { set_current_program_space (SYMTAB_PSPACE (symtab)); - local.objfile = SYMTAB_OBJFILE(symtab); - iterate_over_minimal_symbols (local.objfile, name, add_minsym, - &local); + iterate_over_minimal_symbols + (SYMTAB_OBJFILE (symtab), name, + [&] (struct minimal_symbol *msym) + { + add_minsym (msym, SYMTAB_OBJFILE (symtab), symtab, + info->state->list_mode, &minsyms); + }); } } - if (!VEC_empty (bound_minimal_symbol_d, local.msyms)) - { - int classification; - int ix; - bound_minimal_symbol_d *item; - - qsort (VEC_address (bound_minimal_symbol_d, local.msyms), - VEC_length (bound_minimal_symbol_d, local.msyms), - sizeof (bound_minimal_symbol_d), - compare_msyms); - - /* Now the minsyms are in classification order. So, we walk - over them and process just the minsyms with the same - classification as the very first minsym in the list. */ - item = VEC_index (bound_minimal_symbol_d, local.msyms, 0); - classification = classify_mtype (MSYMBOL_TYPE (item->minsym)); - - for (ix = 0; - VEC_iterate (bound_minimal_symbol_d, local.msyms, ix, item); - ++ix) - { - if (classify_mtype (MSYMBOL_TYPE (item->minsym)) != classification) - break; + if (!minsyms.empty ()) + { + int classification; - VEC_safe_push (bound_minimal_symbol_d, - info->result.minimal_symbols, item); - } - } + std::sort (minsyms.begin (), minsyms.end (), compare_msyms); + + /* Now the minsyms are in classification order. So, we walk + over them and process just the minsyms with the same + classification as the very first minsym in the list. */ + classification = classify_mtype (MSYMBOL_TYPE (minsyms[0].minsym)); + + for (const struct bound_minimal_symbol &item : minsyms) + { + if (classify_mtype (MSYMBOL_TYPE (item.minsym)) != classification) + break; - do_cleanups (cleanup); + VEC_safe_push (bound_minimal_symbol_d, + info->result.minimal_symbols, &item); + } + } } /* A helper function to add all symbols matching NAME to INFO. If @@ -3788,20 +4518,25 @@ search_minsyms_for_name (struct collect_info *info, const char *name, static void add_matching_symbols_to_info (const char *name, + symbol_name_match_type name_match_type, + enum search_domain search_domain, struct collect_info *info, struct program_space *pspace) { int ix; struct symtab *elt; + lookup_name_info lookup_name (name, name_match_type); + for (ix = 0; VEC_iterate (symtab_ptr, info->file_symtabs, ix, elt); ++ix) { if (elt == NULL) { - iterate_over_all_matching_symtabs (info->state, name, VAR_DOMAIN, - collect_symbols, info, - pspace, 1); - search_minsyms_for_name (info, name, pspace, NULL); + iterate_over_all_matching_symtabs (info->state, lookup_name, + VAR_DOMAIN, search_domain, + pspace, true, [&] (symbol *sym) + { return info->add_symbol (sym); }); + search_minsyms_for_name (info, lookup_name, pspace, NULL); } else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt)) { @@ -3811,8 +4546,9 @@ add_matching_symbols_to_info (const char *name, been filtered out earlier. */ gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup); set_current_program_space (SYMTAB_PSPACE (elt)); - iterate_over_file_blocks (elt, name, VAR_DOMAIN, - collect_symbols, info); + iterate_over_file_blocks (elt, lookup_name, VAR_DOMAIN, + [&] (symbol *sym) + { return info->add_symbol (sym); }); /* If no new symbols were found in this iteration and this symtab is in assembler, we might actually be looking for a label for @@ -3820,7 +4556,7 @@ add_matching_symbols_to_info (const char *name, this case. */ if (prev_len == VEC_length (symbolp, info->result.symbols) && elt->language == language_asm) - search_minsyms_for_name (info, name, pspace, elt); + search_minsyms_for_name (info, lookup_name, pspace, elt); } } } @@ -3843,8 +4579,9 @@ symbol_to_sal (struct symtab_and_line *result, { if (SYMBOL_CLASS (sym) == LOC_LABEL && SYMBOL_VALUE_ADDRESS (sym) != 0) { - init_sal (result); + *result = {}; result->symtab = symbol_symtab (sym); + result->symbol = sym; result->line = SYMBOL_LINE (sym); result->pc = SYMBOL_VALUE_ADDRESS (sym); result->pspace = SYMTAB_PSPACE (result->symtab); @@ -3858,9 +4595,11 @@ symbol_to_sal (struct symtab_and_line *result, else if (SYMBOL_LINE (sym) != 0) { /* We know its line number. */ - init_sal (result); + *result = {}; result->symtab = symbol_symtab (sym); + result->symbol = sym; result->line = SYMBOL_LINE (sym); + result->pc = SYMBOL_VALUE_ADDRESS (sym); result->pspace = SYMTAB_PSPACE (result->symtab); return 1; } @@ -3869,45 +4608,10 @@ symbol_to_sal (struct symtab_and_line *result, return 0; } -/* See the comment in linespec.h. */ - -void -init_linespec_result (struct linespec_result *lr) -{ - memset (lr, 0, sizeof (*lr)); -} - -/* See the comment in linespec.h. */ - -void -destroy_linespec_result (struct linespec_result *ls) -{ - int i; - struct linespec_sals *lsal; - - delete_event_location (ls->location); - for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i) - { - xfree (lsal->canonical); - xfree (lsal->sals.sals); - } - VEC_free (linespec_sals, ls->sals); -} - -/* Cleanup function for a linespec_result. */ - -static void -cleanup_linespec_result (void *a) -{ - destroy_linespec_result (a); -} - -/* See the comment in linespec.h. */ - -struct cleanup * -make_cleanup_destroy_linespec_result (struct linespec_result *ls) +linespec_result::~linespec_result () { - return make_cleanup (cleanup_linespec_result, ls); + for (linespec_sals &lsal : lsals) + xfree (lsal.canonical); } /* Return the quote characters permitted by the linespec parser. */