From a245927022bc4351fafd9e6275e217021ec93e08 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 17 Jul 2017 20:24:41 +0100 Subject: [PATCH] Explicit locations -label completer We're missing a completer for (gdb) break -function func -label [TAB] This patch adds one. Tests will be added later in the series. gdb/ChangeLog: 2017-07-17 Pedro Alves * completer.c (collect_explicit_location_matches): Handle MATCH_LABEL. (convert_explicit_location_to_linespec): New, factored out from ... (convert_explicit_location_to_sals): ... this. (complete_label): New. (linespec_complete_label, find_label_symbols_in_block): New. (find_label_symbols): Add completion_mode parameter and adjust to call find_label_symbols_in_block. * linespec.h (linespec_complete_label): Declare. --- gdb/ChangeLog | 13 ++++ gdb/completer.c | 8 +- gdb/linespec.c | 199 ++++++++++++++++++++++++++++++++++++++---------- gdb/linespec.h | 11 +++ 4 files changed, 190 insertions(+), 41 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b341eb162d7..acf0b51e71e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2017-07-17 Pedro Alves + + * completer.c (collect_explicit_location_matches): Handle + MATCH_LABEL. + (convert_explicit_location_to_linespec): New, factored out from + ... + (convert_explicit_location_to_sals): ... this. + (complete_label): New. + (linespec_complete_label, find_label_symbols_in_block): New. + (find_label_symbols): Add completion_mode parameter and adjust to + call find_label_symbols_in_block. + * linespec.h (linespec_complete_label): Declare. + 2017-07-17 Pedro Alves * ada-lang.c (ada_collect_symbol_completion_matches): Add diff --git a/gdb/completer.c b/gdb/completer.c index 1e4fe186197..c2bb4ee50dc 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -627,7 +627,13 @@ collect_explicit_location_matches (completion_tracker &tracker, break; case MATCH_LABEL: - /* Not supported. */ + { + const char *label = string_or_empty (explicit_loc->label_name); + linespec_complete_label (tracker, language, + explicit_loc->source_filename, + explicit_loc->function_name, + label); + } break; default: diff --git a/gdb/linespec.c b/gdb/linespec.c index 20ac71daa4a..0216bf123e6 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -299,7 +299,8 @@ static VEC (symtab_ptr) *symtabs_from_filename (const char *, 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, @@ -2053,31 +2054,33 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls) 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, + 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) + if (source_filename != NULL) { TRY { result->file_symtabs - = symtabs_from_filename (explicit_loc->source_filename, - self->search_pspace); + = 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 { @@ -2085,41 +2088,53 @@ 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, + function_name, &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; +} - return convert_linespec_to_sals (self, result); +/* Convert the explicit location EXPLICIT_LOC into SaLs. */ + +static struct symtabs_and_lines +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->label_name, + explicit_loc->line_offset); + return convert_linespec_to_sals (self, result); } /* Parse a string that specifies a linespec. @@ -2470,6 +2485,69 @@ linespec_complete_function (completion_tracker &tracker, collect_symbol_completion_matches (tracker, mode, function, function); } +/* 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, + 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, + NULL, unknown_offset); + } + CATCH (ex, RETURN_MASK_ERROR) + { + do_cleanups (cleanup); + return; + } + END_CATCH + + complete_label (tracker, &parser, label_name); + + do_cleanups (cleanup); +} + /* A helper function for decode_line_full and decode_line_1 to turn LOCATION into symtabs_and_lines. */ @@ -3385,13 +3463,63 @@ find_linespec_symbols (struct linespec_state *state, } } -/* Return all labels named NAME in FUNCTION_SYMBOLS. Return the - actual function symbol in which the label was found in LABEL_FUNC_RET. */ +/* 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; + + if (sym != NULL) + { + VEC_safe_push (symbolp, *result, sym); + VEC_safe_push (symbolp, *label_funcs_ret, fn_sym); + } + } +} + +/* 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; @@ -3412,13 +3540,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 { @@ -3427,13 +3550,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); } } diff --git a/gdb/linespec.h b/gdb/linespec.h index d55ba122b3e..f16bb81a244 100644 --- a/gdb/linespec.h +++ b/gdb/linespec.h @@ -194,6 +194,17 @@ extern void linespec_complete_function (completion_tracker &tracker, const char *function, const char *source_filename); +/* Complete a label symbol, in linespec mode. Only labels of + functions named FUNCTION_NAME are considered. If SOURCE_FILENAME + is non-NULL, limits completion to labels of functions defined in + source files that match SOURCE_FILENAME. */ + +extern void linespec_complete_label (completion_tracker &tracker, + const struct language_defn *language, + const char *source_filename, + const char *function_name, + const char *label_name); + /* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR, advancing EXP_PTR past any parsed text. */ -- 2.30.2