[PATCH 16/40] Explicit locations -label completer

Pedro Alves
2017-06-02T12:29:17Z

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:
yyyy-mm-dd Pedro Alves <palves@redhat.com>

* 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/completer.c | 8 ++-
gdb/linespec.c | 199 ++++++++++++++++++++++++++++++++++++++++++++------------
gdb/linespec.h | 11 ++++
3 files changed, 177 insertions(+), 41 deletions(-)

diff --git a/gdb/completer.c b/gdb/completer.c
index 0473d8c..c7986e6 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -633,7 +633,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 20ac71d..0216bf1 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<char> (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 d55ba12..f16bb81 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.5.5