* [PATCH 1/2] Add expansion_notify callback to expand_symtabs_matching
2014-02-12 11:55 [PATCH 0/2] Limit tab-completion result when list is large Gary Benson
@ 2014-02-12 11:56 ` Gary Benson
2014-02-12 20:10 ` Tom Tromey
2014-02-12 11:58 ` [PATCH 2/2] Implement completion limiting Gary Benson
1 sibling, 1 reply; 8+ messages in thread
From: Gary Benson @ 2014-02-12 11:56 UTC (permalink / raw)
To: gdb-patches
This patch adds a new callback parameter, "expansion_notify", to the
top-level expand_symtabs_matching function and to all the vectorized
functions it defers to. If expansion_notify is non-NULL, it will be
called every time a psymtab is expanded to a symtab.
gdb/
2014-02-12 Gary Benson <gbenson@redhat.com>
* symfile.h (struct partial_symtab): New forward declaration.
(expand_symtabs_exp_notify_ftype): New typedef.
(struct quick_symbol_functions) <expand_symtabs_matching>: New
parameter "expansion_notify". All uses updated.
(expand_symtabs_matching): Likewise.
* psymtab.c (expand_symtabs_matching_via_partial): New
parameter "expansion_notify". If non-NULL, call it prior
to calling psymtab_to_symtab.
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 17599be..3f7283b 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -35,6 +35,7 @@ struct value;
struct frame_info;
struct agent_expr;
struct axs_value;
+struct partial_symtab;
/* Comparison function for symbol look ups. */
@@ -137,6 +138,13 @@ typedef int (expand_symtabs_file_matcher_ftype) (const char *filename,
typedef int (expand_symtabs_symbol_matcher_ftype) (const char *name,
void *data);
+/* Callback for quick_symbol_functions->expand_symtabs_matching
+ to be notified when a psymtab is expanded. */
+
+typedef void (expand_symtabs_exp_notify_ftype) (struct objfile *objfile,
+ struct partial_symtab *pst,
+ void *data);
+
/* The "quick" symbol functions exist so that symbol readers can
avoiding an initial read of all the symbols. For example, symbol
readers might choose to use the "partial symbol table" utilities,
@@ -282,6 +290,7 @@ struct quick_symbol_functions
(struct objfile *objfile,
expand_symtabs_file_matcher_ftype *file_matcher,
expand_symtabs_symbol_matcher_ftype *symbol_matcher,
+ expand_symtabs_exp_notify_ftype *expansion_notify,
enum search_domain kind,
void *data);
@@ -568,6 +577,7 @@ extern struct cleanup *increment_reading_symtab (void);
void expand_symtabs_matching (expand_symtabs_file_matcher_ftype *,
expand_symtabs_symbol_matcher_ftype *,
+ expand_symtabs_exp_notify_ftype *,
enum search_domain kind, void *data);
void map_symbol_filenames (symbol_filename_ftype *fun, void *data,
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 06d2119..760693f 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -3870,6 +3870,7 @@ symfile_free_objfile (struct objfile *objfile)
void
expand_symtabs_matching (expand_symtabs_file_matcher_ftype *file_matcher,
expand_symtabs_symbol_matcher_ftype *symbol_matcher,
+ expand_symtabs_exp_notify_ftype *expansion_notify,
enum search_domain kind,
void *data)
{
@@ -3879,7 +3880,8 @@ expand_symtabs_matching (expand_symtabs_file_matcher_ftype *file_matcher,
{
if (objfile->sf)
objfile->sf->qf->expand_symtabs_matching (objfile, file_matcher,
- symbol_matcher, kind,
+ symbol_matcher,
+ expansion_notify, kind,
data);
}
}
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index a10d800..62b9206 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -6170,8 +6170,8 @@ ada_make_symbol_completion_list (const char *text0, const char *word,
data.word = word;
data.wild_match = wild_match_p;
data.encoded = encoded_p;
- expand_symtabs_matching (NULL, ada_complete_symbol_matcher, ALL_DOMAIN,
- &data);
+ expand_symtabs_matching (NULL, ada_complete_symbol_matcher, NULL,
+ ALL_DOMAIN, &data);
}
/* At this point scan through the misc symbol vectors and add each
@@ -12751,7 +12751,7 @@ ada_add_global_exceptions (regex_t *preg, VEC(ada_exc_info) **exceptions)
struct objfile *objfile;
struct symtab *s;
- expand_symtabs_matching (NULL, ada_exc_search_name_matches,
+ expand_symtabs_matching (NULL, ada_exc_search_name_matches, NULL,
VARIABLES_DOMAIN, preg);
ALL_PRIMARY_SYMTABS (objfile, s)
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 54c538a..f9da5db 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -3773,6 +3773,7 @@ dw2_expand_symtabs_matching
(struct objfile *objfile,
expand_symtabs_file_matcher_ftype *file_matcher,
expand_symtabs_symbol_matcher_ftype *symbol_matcher,
+ expand_symtabs_exp_notify_ftype *expansion_notify,
enum search_domain kind,
void *data)
{
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 4b596fc..726d081 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1029,7 +1029,7 @@ iterate_over_all_matching_symtabs (struct linespec_state *state,
if (objfile->sf)
objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
iterate_name_matcher,
- ALL_DOMAIN,
+ NULL, ALL_DOMAIN,
&matcher_data);
ALL_OBJFILE_PRIMARY_SYMTABS (objfile, symtab)
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index c247bd7..9671ea1 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -287,22 +287,25 @@ debug_qf_expand_symtabs_matching
(struct objfile *objfile,
expand_symtabs_file_matcher_ftype *file_matcher,
expand_symtabs_symbol_matcher_ftype *symbol_matcher,
+ expand_symtabs_exp_notify_ftype *expansion_notify,
enum search_domain kind, void *data)
{
const struct debug_sym_fns_data *debug_data =
objfile_data (objfile, symfile_debug_objfile_data_key);
fprintf_filtered (gdb_stdlog,
- "qf->expand_symtabs_matching (%s, %s, %s, %s, %s)\n",
+ "qf->expand_symtabs_matching (%s, %s, %s, %s, %s, %s)\n",
debug_objfile_name (objfile),
host_address_to_string (file_matcher),
host_address_to_string (symbol_matcher),
+ host_address_to_string (expansion_notify),
search_domain_name (kind),
host_address_to_string (data));
debug_data->real_sf->qf->expand_symtabs_matching (objfile,
file_matcher,
symbol_matcher,
+ expansion_notify,
kind, data);
}
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 4064e06..2bd7bc0 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -897,7 +897,7 @@ maintenance_expand_symtabs (char *args, int from_tty)
{
objfile->sf->qf->expand_symtabs_matching
(objfile, maintenance_expand_file_matcher,
- maintenance_expand_name_matcher, ALL_DOMAIN, regexp);
+ maintenance_expand_name_matcher, NULL, ALL_DOMAIN, regexp);
}
}
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 50c09c1..6b94713 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3625,7 +3625,7 @@ search_symbols (char *regexp, enum search_domain kind,
? NULL
: search_symbols_file_matches),
search_symbols_name_matches,
- kind, &datum);
+ NULL, kind, &datum);
/* Here, we search through the minimal symbol tables for functions
and variables that match, and force their symbols to be read.
@@ -4405,8 +4405,8 @@ default_make_symbol_completion_list_break_on (const char *text,
/* Look through the partial symtabs for all symbols which begin
by matching SYM_TEXT. Expand all CUs that you find to the list.
The real names will get added by COMPLETION_LIST_ADD_SYMBOL below. */
- expand_symtabs_matching (NULL, symbol_completion_matcher, ALL_DOMAIN,
- &datum);
+ expand_symtabs_matching (NULL, symbol_completion_matcher, NULL,
+ ALL_DOMAIN, &datum);
/* At this point scan through the misc symbol vectors and add each
symbol you find to the list. Eventually we want to ignore
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 457b91a..e742e87 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1365,6 +1365,7 @@ expand_symtabs_matching_via_partial
(struct objfile *objfile,
expand_symtabs_file_matcher_ftype *file_matcher,
expand_symtabs_symbol_matcher_ftype *symbol_matcher,
+ expand_symtabs_exp_notify_ftype *expansion_notify,
enum search_domain kind,
void *data)
{
@@ -1407,7 +1408,12 @@ expand_symtabs_matching_via_partial
}
if (recursively_search_psymtabs (ps, objfile, kind, symbol_matcher, data))
- psymtab_to_symtab (objfile, ps);
+ {
+ if (expansion_notify != NULL)
+ expansion_notify (objfile, ps, data);
+
+ psymtab_to_symtab (objfile, ps);
+ }
}
}
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 2/2] Implement completion limiting
2014-02-12 11:55 [PATCH 0/2] Limit tab-completion result when list is large Gary Benson
2014-02-12 11:56 ` [PATCH 1/2] Add expansion_notify callback to expand_symtabs_matching Gary Benson
@ 2014-02-12 11:58 ` Gary Benson
2014-02-12 16:27 ` Eli Zaretskii
2014-02-12 16:41 ` Pedro Alves
1 sibling, 2 replies; 8+ messages in thread
From: Gary Benson @ 2014-02-12 11:58 UTC (permalink / raw)
To: gdb-patches
This patch adds a new exception, TOO_MANY_COMPLETIONS_ERROR, to be
thrown whenever the completer has generated too many possibilities to
be useful. A new user-settable variable, "max_completions", is added
to control this behaviour.
gdb/
2014-02-12 Gary Benson <gbenson@redhat.com>
* exceptions.h (enum errors) <TOO_MANY_COMPLETIONS_ERROR>:
New error.
* completer.c: Include TUI headers when appropriate.
(max_completions): New variable.
(complete_line): Added completion limiting logic and
associated cleanup.
(line_completion_function): Handle TOO_MANY_COMPLETIONS_ERROR.
(limit_completions): New function.
(_initialize_completer): Likewise.
* completer.h (limit_completions): New declaration.
* symtab.c: Include psymtab.h, psympriv.h and completer.h.
(struct add_name_data) <n_global_syms>: New field.
(halt_large_expansions): New function.
(default_make_symbol_completion_list_break_on): Added
completion limiting logic.
gdb/doc/
2014-02-12 Gary Benson <gbenson@redhat.com>
* gdb.texinfo (Command Completion): Document new
"set/show max-completions" option.
gdb/testsuite/
2014-02-12 Gary Benson <gbenson@redhat.com>
* gdb.base/completion.exp: Test completion limiting.
diff --git a/gdb/exceptions.h b/gdb/exceptions.h
index b8dadc7..1b9c1ef 100644
--- a/gdb/exceptions.h
+++ b/gdb/exceptions.h
@@ -100,6 +100,9 @@ enum errors {
/* Requested feature, method, mechanism, etc. is not supported. */
NOT_SUPPORTED_ERROR,
+ /* Too many possibilities were encountered during line completion. */
+ TOO_MANY_COMPLETIONS_ERROR,
+
/* Add more errors here. */
NR_ERRORS
};
diff --git a/gdb/completer.c b/gdb/completer.c
index 94f70a9..31e300f 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -41,6 +41,11 @@
#include "completer.h"
+#ifdef TUI
+#include "tui/tui.h"
+#include "tui/tui-io.h"
+#endif
+
/* Prototypes for local functions. */
static
char *line_completion_function (const char *text, int matches,
@@ -759,9 +764,17 @@ complete_line_internal (const char *text,
return list;
}
-/* Generate completions all at once. Returns a vector of strings.
- Each element is allocated with xmalloc. It can also return NULL if
- there are no completions.
+
+/* Maximum number of possibilities to consider before the completer
+ bails by throwing TOO_MANY_COMPLETIONS_ERROR. If set to -1 then
+ no limiting will be performed. */
+static int max_completions = 1000;
+
+/* Generate completions all at once. Returns a vector of strings
+ allocated with xmalloc. Returns NULL if there are no completions
+ or if max_completions is 0. Throws TOO_MANY_COMPLETIONS_ERROR if
+ max_completions is greater than zero and the number of completions
+ is greater than max_completions.
TEXT is the caller's idea of the "word" we are looking at.
@@ -774,8 +787,26 @@ complete_line_internal (const char *text,
VEC (char_ptr) *
complete_line (const char *text, char *line_buffer, int point)
{
- return complete_line_internal (text, line_buffer,
- point, handle_completions);
+ VEC (char_ptr) *list = NULL;
+
+ if (max_completions != 0)
+ {
+ struct cleanup *back_to;
+
+ list = complete_line_internal (text, line_buffer,
+ point, handle_completions);
+ back_to = make_cleanup_free_char_ptr_vec (list);
+
+ /* Possibly throw TOO_MANY_COMPLETIONS_ERROR. Individual
+ completers may do this too, to avoid unnecessary work,
+ but this is the ultimate check that stops users seeing
+ more completions than they wanted. */
+ limit_completions (VEC_length (char_ptr, list));
+
+ discard_cleanups (back_to);
+ }
+
+ return list;
}
/* Complete on command names. Used by "help". */
@@ -862,6 +893,8 @@ line_completion_function (const char *text, int matches,
if (matches == 0)
{
+ volatile struct gdb_exception ex;
+
/* The caller is beginning to accumulate a new set of
completions, so we need to find all of them now, and cache
them for returning one at a time on future calls. */
@@ -875,7 +908,35 @@ line_completion_function (const char *text, int matches,
VEC_free (char_ptr, list);
}
index = 0;
- list = complete_line (text, line_buffer, point);
+
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ list = complete_line (text, line_buffer, point);
+
+ if (ex.reason < 0)
+ {
+ if (ex.error != TOO_MANY_COMPLETIONS_ERROR)
+ throw_exception (ex);
+
+ if (rl_completion_type != TAB)
+ {
+#if defined(TUI)
+ if (tui_active)
+ {
+ tui_puts ("\n");
+ tui_puts (ex.message);
+ tui_puts ("\n");
+ }
+ else
+#endif
+ {
+ rl_crlf ();
+ fputs (ex.message, rl_outstream);
+ rl_crlf ();
+ }
+
+ rl_on_new_line ();
+ }
+ }
}
/* If we found a list of potential completions during initialization
@@ -959,3 +1020,31 @@ skip_quoted (const char *str)
{
return skip_quoted_chars (str, NULL, NULL);
}
+
+/* Throw TOO_MANY_COMPLETIONS_ERROR if max_completions is greater than
+ zero and NUM_COMPLETIONS is greater than max_completions. Negative
+ values of max_completions disable limiting. */
+
+void
+limit_completions (int num_completions)
+{
+ if (max_completions >= 0 && num_completions > max_completions)
+ throw_error (TOO_MANY_COMPLETIONS_ERROR,
+ _("Too many possibilities."));
+}
+
+extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
+
+void
+_initialize_completer (void)
+{
+ add_setshow_zuinteger_unlimited_cmd ("max-completions", no_class,
+ &max_completions, _("\
+Set maximum number of line completion possibilities."), _("\
+Show maximum number of line completion possibilities."), _("\
+Use this to limit the number of possibilities considered\n\
+during line completion. Specifying \"unlimited\" or -1\n\
+disables limiting. Note that setting either no limit or\n\
+a very large limit can cause pauses during completion."),
+ NULL, NULL, &setlist, &showlist);
+}
diff --git a/gdb/completer.h b/gdb/completer.h
index 5b90773..58c726d 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -48,6 +48,8 @@ extern char *get_gdb_completer_quote_characters (void);
extern char *gdb_completion_word_break_characters (void);
+extern void limit_completions (int);
+
/* Exported to linespec.c */
extern const char *skip_quoted_chars (const char *, const char *,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 0b5d34a..9faf496 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -62,6 +62,9 @@
#include "macroscope.h"
#include "parser-defs.h"
+#include "psymtab.h"
+#include "psympriv.h"
+#include "completer.h"
/* Prototypes for local functions */
@@ -4274,6 +4277,7 @@ struct add_name_data
int sym_text_len;
const char *text;
const char *word;
+ int n_global_syms;
};
/* A callback used with macro_for_each and macro_for_each_in_scope.
@@ -4301,6 +4305,23 @@ symbol_completion_matcher (const char *name, void *user_data)
return compare_symbol_name (name, datum->sym_text, datum->sym_text_len);
}
+/* A callback for expand_partial_symbol_names, used to abort line
+ completion before large numbers of symbols have been expanded.
+ Without this check GDB can appear to lock up during some line
+ completions. This is an inexact but worst-case check, in that
+ there will be more than the threshold number of completions
+ available by the time limit_completions bails. */
+
+static void
+halt_large_expansions (struct objfile *objfile,
+ struct partial_symtab *pst, void *user_data)
+{
+ struct add_name_data *datum = (struct add_name_data *) user_data;
+
+ datum->n_global_syms += pst->n_global_syms;
+ limit_completions (datum->n_global_syms);
+}
+
VEC (char_ptr) *
default_make_symbol_completion_list_break_on (const char *text,
const char *word,
@@ -4401,12 +4422,13 @@ default_make_symbol_completion_list_break_on (const char *text,
datum.sym_text_len = sym_text_len;
datum.text = text;
datum.word = word;
+ datum.n_global_syms = 0;
/* Look through the partial symtabs for all symbols which begin
by matching SYM_TEXT. Expand all CUs that you find to the list.
The real names will get added by COMPLETION_LIST_ADD_SYMBOL below. */
- expand_symtabs_matching (NULL, symbol_completion_matcher, NULL,
- ALL_DOMAIN, &datum);
+ expand_symtabs_matching (NULL, symbol_completion_matcher,
+ halt_large_expansions, ALL_DOMAIN, &datum);
/* At this point scan through the misc symbol vectors and add each
symbol you find to the list. Eventually we want to ignore
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 035573e..8d7a6fe 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1597,6 +1597,30 @@ means @kbd{@key{META} ?}. You can type this either by holding down a
key designated as the @key{META} shift on your keyboard (if there is
one) while typing @kbd{?}, or as @key{ESC} followed by @kbd{?}.
+If the number of possible completions is large, @value{GDBN} will
+print a message rather than displaying the list:
+
+@smallexample
+(@value{GDBP}) b @key{TAB}@key{TAB}
+Too many possibilities.
+@end smallexample
+
+@noindent
+This behavior can be controlled with the following commands:
+
+@table @code
+@kindex set max-completions
+@item set max-completions @var{limit}
+@itemx set max-completions unlimited
+Set the maximum number of possibilities to be considered during
+completion. The default value is 1000. Note that setting either
+no limit or a very large limit can cause pauses during completion.
+@kindex show max-completions
+@item show max-completions
+Show the maximum number of possibilities to be considered during
+completion.
+@end table
+
@cindex quotes in commands
@cindex completion of quoted strings
Sometimes the string you need, while logically a ``word'', may contain
diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp
index d51a847..721c17a 100644
--- a/gdb/testsuite/gdb.base/completion.exp
+++ b/gdb/testsuite/gdb.base/completion.exp
@@ -69,6 +69,8 @@ if ![runto_main] then {
set oldtimeout1 $timeout
set timeout 30
+gdb_test_no_output "set max-completions unlimited"
+
set test "complete 'hfgfh'"
send_gdb "hfgfh\t"
gdb_test_multiple "" "$test" {
@@ -729,6 +731,38 @@ gdb_test "complete set listsize unl" "set listsize unlimited"
gdb_test "complete set trace-buffer-size " "set trace-buffer-size unlimited"
gdb_test "complete set trace-buffer-size unl" "set trace-buffer-size unlimited"
+#
+# Completion limiting.
+#
+
+gdb_test_no_output "set max-completions 5"
+
+set test "completion limiting using tab character"
+send_gdb "p\t"
+gdb_test_multiple "" "$test" {
+ -re "^p\\\x07$" {
+ send_gdb "\t"
+ gdb_test_multiple "" "$test" {
+ -re "Too many possibilities.\r\n\\\x07$gdb_prompt p$" {
+ send_gdb "\n"
+ gdb_test_multiple "" "$test" {
+ -re "$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+ }
+ }
+ }
+}
+
+set test "completion limiting using complete command"
+send_gdb "complete p\n"
+gdb_test_multiple "" "$test" {
+ -re "Too many possibilities.\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+}
+
# Restore globals modified in this test...
set timeout $oldtimeout1
^ permalink raw reply [flat|nested] 8+ messages in thread