From patchwork Sat Jan 31 23:30:24 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 4861 Received: (qmail 23326 invoked by alias); 31 Jan 2015 23:31:17 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 23316 invoked by uid 89); 31 Jan 2015 23:31:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_00, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pa0-f53.google.com Received: from mail-pa0-f53.google.com (HELO mail-pa0-f53.google.com) (209.85.220.53) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Sat, 31 Jan 2015 23:31:13 +0000 Received: by mail-pa0-f53.google.com with SMTP id kx10so66756422pab.12 for ; Sat, 31 Jan 2015 15:31:11 -0800 (PST) X-Received: by 10.68.131.39 with SMTP id oj7mr18748335pbb.145.1422747071711; Sat, 31 Jan 2015 15:31:11 -0800 (PST) Received: from seba.sebabeach.org.gmail.com (173-13-178-53-sfba.hfc.comcastbusiness.net. [173.13.178.53]) by mx.google.com with ESMTPSA id c9sm14647846pdm.51.2015.01.31.15.31.09 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 31 Jan 2015 15:31:10 -0800 (PST) From: Doug Evans To: Eli Zaretskii Cc: gbenson@redhat.com, gdb-patches@sourceware.org Subject: Re: [PATCH 3/3 v2] Implement completion limiting References: <1417094168-25868-1-git-send-email-gbenson@redhat.com> <1417094168-25868-4-git-send-email-gbenson@redhat.com> <20141210122233.GA7299@blade.nx> <21671.20308.262958.475080@ruffy2.mtv.corp.google.com> <20150107084255.GA17867@blade.nx> <21680.36641.315766.209208@ruffy2.mtv.corp.google.com> <83a91r6lbd.fsf@gnu.org> <20150115153930.GA14900@blade.nx> <83h9vhu7k8.fsf@gnu.org> <83zj99sbgk.fsf@gnu.org> <83wq4ds0lh.fsf@gnu.org> <83k30csgu7.fsf@gnu.org> <83sieyrg5w.fsf@gnu.org> Date: Sat, 31 Jan 2015 15:30:24 -0800 In-Reply-To: <83sieyrg5w.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 25 Jan 2015 18:14:35 +0200") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-IsSubscribed: yes Eli Zaretskii writes: >> From: Doug Evans >> Cc: gbenson@redhat.com, gdb-patches@sourceware.org >> Date: Sat, 24 Jan 2015 17:11:24 -0800 >> >> +@item set max-completions @var{limit} >> +@itemx set max-completions unlimited >> +Set the maximum number of candidates that @value{GDBN} will collect >> +and show during completion. > > I'd prefer saying this more explicitly, for example: > > Set the maximum number of completion candidates. @value{GDBN} will > stop looking for more completions once it collects this many > candidates. > > WDYT? Done. Here is what I committed, in addition the 1/3 and 2/3 patches of the series. Thanks Gary for the core bits that made this possible. 2015-01-22 Gary Benson Doug Evans PR cli/9007 PR cli/11920 PR cli/15548 * cli/cli-cmds.c (complete_command): Notify user if max-completions reached. * common/common-exceptions.h (enum errors) : New value. * completer.h (get_max_completions_reached_message): New declaration. (max_completions): Likewise. (completion_tracker_t): New typedef. (new_completion_tracker): New declaration. (make_cleanup_free_completion_tracker): Likewise. (maybe_add_completion_enum): New enum. (maybe_add_completion): New declaration. (throw_max_completions_reached_error): Likewise. * completer.c (max_completions): New global variable. (new_completion_tracker): New function. (free_completion_tracker): Likewise. (make_cleanup_free_completion_tracker): Likewise. (maybe_add_completions): Likewise. (throw_max_completions_reached_error): Likewise. (complete_line): Remove duplicates and limit result to max_completions entries. (get_max_completions_reached_message): New function. (gdb_display_match_list): Handle max_completions. (_initialize_completer): New declaration and function. * symtab.c: Include completer.h. (completion_tracker): New static variable. (completion_list_add_name): Call maybe_add_completion. (default_make_symbol_completion_list_break_on_1): Renamed from default_make_symbol_completion_list_break_on. Maintain completion_tracker across calls to completion_list_add_name. (default_make_symbol_completion_list_break_on): New function. * top.c (init_main): Set rl_completion_display_matches_hook. * tui/tui-io.c: Include completer.h. (tui_old_rl_display_matches_hook): New static global. (tui_rl_display_match_list): Notify user if max-completions reached. (tui_setup_io): Save/restore rl_completion_display_matches_hook. * NEWS (New Options): Mention set/show max-completions. doc/ * gdb.texinfo (Command Completion): Document new "set/show max-completions" option. testsuite/ * gdb.base/completion.exp: Disable completion limiting for existing tests. Add new tests to check completion limiting. * gdb.linespec/ls-errs.exp: Disable completion limiting. diff --git a/gdb/NEWS b/gdb/NEWS index 2d2c941..09a5742 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,15 @@ *** Changes since GDB 7.9 +* New options + +set max-completions +show max-completions + Set the maximum number of candidates to be considered during + completion. The default value is 200. This limit allows GDB + to avoid generating large completion lists, the computation of + which can cause the debugger to become temporarily unresponsive. + *** Changes in GDB 7.9 * GDB now supports hardware watchpoints on x86 GNU Hurd. diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index e20d8dd..e46f036 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -236,7 +236,8 @@ help_command (char *command, int from_tty) help_cmd (command, gdb_stdout); } -/* The "complete" command is used by Emacs to implement completion. */ +/* Note: The "complete" command is used by Emacs to implement completion. + [Is that why this function writes output with *_unfiltered?] */ static void complete_command (char *arg, int from_tty) @@ -247,6 +248,18 @@ complete_command (char *arg, int from_tty) dont_repeat (); + if (max_completions == 0) + { + /* Only print this for non-mi frontends. An MI frontend may not + be able to handle this. */ + if (!ui_out_is_mi_like_p (current_uiout)) + { + printf_unfiltered (_("max-completions is zero," + " completion is disabled.\n")); + } + return; + } + if (arg == NULL) arg = ""; argpoint = strlen (arg); @@ -293,6 +306,15 @@ complete_command (char *arg, int from_tty) xfree (prev); VEC_free (char_ptr, completions); + + if (size == max_completions) + { + /* ARG_PREFIX and POINT are included in the output so that emacs + will include the message in the output. */ + printf_unfiltered (_("%s%s %s\n"), + arg_prefix, point, + get_max_completions_reached_message ()); + } } } diff --git a/gdb/common/common-exceptions.h b/gdb/common/common-exceptions.h index 4f60ad8..e349ed0 100644 --- a/gdb/common/common-exceptions.h +++ b/gdb/common/common-exceptions.h @@ -99,6 +99,12 @@ enum errors { /* Requested feature, method, mechanism, etc. is not supported. */ NOT_SUPPORTED_ERROR, + /* The number of candidates generated during line completion has + reached the user's specified limit. This isn't an error, this exception + is used to halt searching for more completions, but for consistency + "_ERROR" is appended to the name. */ + MAX_COMPLETIONS_REACHED_ERROR, + /* Add more errors here. */ NR_ERRORS }; diff --git a/gdb/completer.c b/gdb/completer.c index 88c8e16..287e9dc 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -781,9 +781,93 @@ 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. + +/* See completer.h. */ + +int max_completions = 200; + +/* See completer.h. */ + +completion_tracker_t +new_completion_tracker (void) +{ + if (max_completions <= 0) + return NULL; + + return htab_create_alloc (max_completions, + htab_hash_string, (htab_eq) streq, + NULL, xcalloc, xfree); +} + +/* Cleanup routine to free a completion tracker and reset the pointer + to NULL. */ + +static void +free_completion_tracker (void *p) +{ + completion_tracker_t *tracker_ptr = p; + + htab_delete (*tracker_ptr); + *tracker_ptr = NULL; +} + +/* See completer.h. */ + +struct cleanup * +make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr) +{ + if (*tracker_ptr == NULL) + return make_cleanup (null_cleanup, NULL); + + return make_cleanup (free_completion_tracker, tracker_ptr); +} + +/* See completer.h. */ + +enum maybe_add_completion_enum +maybe_add_completion (completion_tracker_t tracker, char *name) +{ + void **slot; + + if (max_completions < 0) + return MAYBE_ADD_COMPLETION_OK; + if (max_completions == 0) + return MAYBE_ADD_COMPLETION_MAX_REACHED; + + gdb_assert (tracker != NULL); + + if (htab_elements (tracker) >= max_completions) + return MAYBE_ADD_COMPLETION_MAX_REACHED; + + slot = htab_find_slot (tracker, name, INSERT); + + if (*slot != HTAB_EMPTY_ENTRY) + return MAYBE_ADD_COMPLETION_DUPLICATE; + + *slot = name; + + return (htab_elements (tracker) < max_completions + ? MAYBE_ADD_COMPLETION_OK + : MAYBE_ADD_COMPLETION_OK_MAX_REACHED); +} + +void +throw_max_completions_reached_error (void) +{ + throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached.")); +} + +/* Generate completions all at once. Returns a vector of unique strings + allocated with xmalloc. Returns NULL if there are no completions + or if max_completions is 0. If max_completions is non-negative, this will + return at most max_completions + 1 strings. + + If max_completions strings are collected, an extra string is added which + is a text message to inform the user that the list may be truncated. + This extra string serves two purposes: + 1) Inform the user. + 2) Prevent readline from being able to find a common prefix to advance + point to, since it's working with an incomplete list. TEXT is the caller's idea of the "word" we are looking at. @@ -796,8 +880,58 @@ complete_line_internal (const char *text, VEC (char_ptr) * complete_line (const char *text, const char *line_buffer, int point) { - return complete_line_internal (text, line_buffer, - point, handle_completions); + VEC (char_ptr) *list; + VEC (char_ptr) *result = NULL; + struct cleanup *cleanups; + completion_tracker_t tracker; + char *candidate; + int ix, max_reached; + + if (max_completions == 0) + return NULL; + list = complete_line_internal (text, line_buffer, point, + handle_completions); + if (max_completions < 0) + return list; + + tracker = new_completion_tracker (); + cleanups = make_cleanup_free_completion_tracker (&tracker); + make_cleanup_free_char_ptr_vec (list); + + /* Do a final test for too many completions. Individual completers may + do some of this, but are not required to. Duplicates are also removed + here. Otherwise the user is left scratching his/her head: readline and + complete_command will remove duplicates, and if removal of duplicates + there brings the total under max_completions the user may think gdb quit + searching too early. */ + + for (ix = 0, max_reached = 0; + !max_reached && VEC_iterate (char_ptr, list, ix, candidate); + ++ix) + { + enum maybe_add_completion_enum add_status; + + add_status = maybe_add_completion (tracker, candidate); + + switch (add_status) + { + case MAYBE_ADD_COMPLETION_OK: + VEC_safe_push (char_ptr, result, xstrdup (candidate)); + break; + case MAYBE_ADD_COMPLETION_OK_MAX_REACHED: + VEC_safe_push (char_ptr, result, xstrdup (candidate)); + max_reached = 1; + break; + case MAYBE_ADD_COMPLETION_MAX_REACHED: + gdb_assert_not_reached ("more than max completions reached"); + case MAYBE_ADD_COMPLETION_DUPLICATE: + break; + } + } + + do_cleanups (cleanups); + + return result; } /* Complete on command names. Used by "help". */ @@ -1020,6 +1154,15 @@ skip_quoted (const char *str) { return skip_quoted_chars (str, NULL, NULL); } + +/* Return a message indicating that the maximum number of completions + has been reached and that there may be more. */ + +const char * +get_max_completions_reached_message (void) +{ + return _("*** List may be truncated, max-completions reached. ***"); +} /* GDB replacement for rl_display_match_list. Readline doesn't provide a clean interface for TUI(curses). @@ -1413,9 +1556,10 @@ gdb_complete_get_screenwidth (const struct match_list_displayer *displayer) } /* GDB version of readline/complete.c:rl_display_match_list. - See gdb_display_match_list for a description of MATCHES, LEN, MAX. */ + See gdb_display_match_list for a description of MATCHES, LEN, MAX. + Returns non-zero if all matches are displayed. */ -static void +static int gdb_display_match_list_1 (char **matches, int len, int max, const struct match_list_displayer *displayer) { @@ -1501,7 +1645,7 @@ gdb_display_match_list_1 (char **matches, int len, int max, { lines = gdb_display_match_list_pager (lines, displayer); if (lines < 0) - return; + return 0; } } } @@ -1523,7 +1667,7 @@ gdb_display_match_list_1 (char **matches, int len, int max, { lines = gdb_display_match_list_pager (lines, displayer); if (lines < 0) - return; + return 0; } } else @@ -1533,6 +1677,8 @@ gdb_display_match_list_1 (char **matches, int len, int max, } displayer->crlf (displayer); } + + return 1; } /* Utility for displaying completion list matches, used by both CLI and TUI. @@ -1550,6 +1696,13 @@ void gdb_display_match_list (char **matches, int len, int max, const struct match_list_displayer *displayer) { + /* Readline will never call this if complete_line returned NULL. */ + gdb_assert (max_completions != 0); + + /* complete_line will never return more than this. */ + if (max_completions > 0) + gdb_assert (len <= max_completions); + if (rl_completion_query_items > 0 && len >= rl_completion_query_items) { char msg[100]; @@ -1572,5 +1725,33 @@ gdb_display_match_list (char **matches, int len, int max, } } - gdb_display_match_list_1 (matches, len, max, displayer); + if (gdb_display_match_list_1 (matches, len, max, displayer)) + { + /* Note: MAX_COMPLETIONS may be -1 or zero, but LEN is always > 0. */ + if (len == max_completions) + { + /* The maximum number of completions has been reached. Warn the user + that there may be more. */ + const char *message = get_max_completions_reached_message (); + + displayer->puts (displayer, message); + displayer->crlf (displayer); + } + } +} + +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 completion candidates."), _("\ +Show maximum number of completion candidates."), _("\ +Use this to limit the number of candidates considered\n\ +during completion. Specifying \"unlimited\" or -1\n\ +disables limiting. Note that setting either no limit or\n\ +a very large limit can make completion slow."), + NULL, NULL, &setlist, &showlist); } diff --git a/gdb/completer.h b/gdb/completer.h index dbb1cfb..56e1a2b 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -66,6 +66,8 @@ struct match_list_displayer extern void gdb_display_match_list (char **matches, int len, int max, const struct match_list_displayer *); +extern const char *get_max_completions_reached_message (void); + extern VEC (char_ptr) *complete_line (const char *text, const char *line_buffer, int point); @@ -112,4 +114,68 @@ extern const char *skip_quoted_chars (const char *, const char *, extern const char *skip_quoted (const char *); +/* Maximum number of candidates to consider before the completer + bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values + disable limiting. */ + +extern int max_completions; + +/* Object to track how many unique completions have been generated. + Used to limit the size of generated completion lists. */ + +typedef htab_t completion_tracker_t; + +/* Create a new completion tracker. + The result is a hash table to track added completions, or NULL + if max_completions <= 0. If max_completions < 0, tracking is disabled. + If max_completions == 0, the max is indeed zero. */ + +extern completion_tracker_t new_completion_tracker (void); + +/* Make a cleanup to free a completion tracker, and reset its pointer + to NULL. */ + +extern struct cleanup *make_cleanup_free_completion_tracker + (completion_tracker_t *tracker_ptr); + +/* Return values for maybe_add_completion. */ + +enum maybe_add_completion_enum +{ + /* NAME has been recorded and max_completions has not been reached, + or completion tracking is disabled (max_completions < 0). */ + MAYBE_ADD_COMPLETION_OK, + + /* NAME has been recorded and max_completions has been reached + (thus the caller can stop searching). */ + MAYBE_ADD_COMPLETION_OK_MAX_REACHED, + + /* max-completions entries has been reached. + Whether NAME is a duplicate or not is not determined. */ + MAYBE_ADD_COMPLETION_MAX_REACHED, + + /* NAME has already been recorded. + Note that this is never returned if completion tracking is disabled + (max_completions < 0). */ + MAYBE_ADD_COMPLETION_DUPLICATE +}; + +/* Add the completion NAME to the list of generated completions if + it is not there already. + If max_completions is negative, nothing is done, not even watching + for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned. + + If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to + record at least one more completion. The final list will be pruned to + max_completions, but recording at least one more than max_completions is + the signal to the completion machinery that too many completions were + found. */ + +extern enum maybe_add_completion_enum + maybe_add_completion (completion_tracker_t tracker, char *name); + +/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */ + +extern void throw_max_completions_reached_error (void); + #endif /* defined (COMPLETER_H) */ diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index f413e23..3a1239e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1600,6 +1600,38 @@ 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 as much of the list as it has collected, as well as a message +indicating that the list may be truncated. + +@smallexample +(@value{GDBP}) b m@key{TAB}@key{TAB} +main +<... the rest of the possible completions ...> +*** List may be truncated, max-completions reached. *** +(@value{GDBP}) b m +@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 candidates that @value{GDBN} will collect +and show during completion. This is useful when completing on things +like function names as collecting all the possible candidates can be +time consuming. +The default value is 200. A value of zero disables tab-completion. +Note that setting either no limit or a very large limit can make +completion slow. +@kindex show max-completions +@item show max-completions +Show the maximum number of candidates that @value{GDBN} will collect and show +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/symtab.c b/gdb/symtab.c index 94b04fb..1d3d8ee 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -60,6 +60,7 @@ #include "macroscope.h" #include "parser-defs.h" +#include "completer.h" /* Forward declarations for local functions. */ @@ -4309,6 +4310,15 @@ static VEC (char_ptr) *return_val; completion_list_add_name \ (MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word)) +/* Tracker for how many unique completions have been generated. Used + to terminate completion list generation early if the list has grown + to a size so large as to be useless. This helps avoid GDB seeming + to lock up in the event the user requests to complete on something + vague that necessitates the time consuming expansion of many symbol + tables. */ + +static completion_tracker_t completion_tracker; + /* Test to see if the symbol specified by SYMNAME (which is already demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN characters. If so, add it to the current completion list. */ @@ -4327,6 +4337,7 @@ completion_list_add_name (const char *symname, { char *new; + enum maybe_add_completion_enum add_status; if (word == sym_text) { @@ -4348,7 +4359,22 @@ completion_list_add_name (const char *symname, strcat (new, symname); } - VEC_safe_push (char_ptr, return_val, new); + add_status = maybe_add_completion (completion_tracker, new); + + switch (add_status) + { + case MAYBE_ADD_COMPLETION_OK: + VEC_safe_push (char_ptr, return_val, new); + break; + case MAYBE_ADD_COMPLETION_OK_MAX_REACHED: + VEC_safe_push (char_ptr, return_val, new); + throw_max_completions_reached_error (); + case MAYBE_ADD_COMPLETION_MAX_REACHED: + throw_max_completions_reached_error (); + case MAYBE_ADD_COMPLETION_DUPLICATE: + xfree (new); + break; + } } } @@ -4561,11 +4587,11 @@ symtab_expansion_callback (struct compunit_symtab *symtab, datum->code); } -VEC (char_ptr) * -default_make_symbol_completion_list_break_on (const char *text, - const char *word, - const char *break_on, - enum type_code code) +static void +default_make_symbol_completion_list_break_on_1 (const char *text, + const char *word, + const char *break_on, + enum type_code code) { /* Problem: All of the symbols have to be copied because readline frees them. I'm not going to worry about this; hopefully there @@ -4583,7 +4609,7 @@ default_make_symbol_completion_list_break_on (const char *text, /* Length of sym_text. */ int sym_text_len; struct add_name_data datum; - struct cleanup *back_to; + struct cleanup *cleanups; /* Now look for the symbol we are supposed to complete on. */ { @@ -4618,7 +4644,7 @@ default_make_symbol_completion_list_break_on (const char *text, /* A double-quoted string is never a symbol, nor does it make sense to complete it any other way. */ { - return NULL; + return; } else { @@ -4654,8 +4680,8 @@ default_make_symbol_completion_list_break_on (const char *text, } gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '('); - return_val = NULL; - back_to = make_cleanup (do_free_completion_list, &return_val); + completion_tracker = new_completion_tracker (); + cleanups = make_cleanup_free_completion_tracker (&completion_tracker); datum.sym_text = sym_text; datum.sym_text_len = sym_text_len; @@ -4769,8 +4795,34 @@ default_make_symbol_completion_list_break_on (const char *text, macro_for_each (macro_user_macros, add_macro_name, &datum); } + do_cleanups (cleanups); +} + +VEC (char_ptr) * +default_make_symbol_completion_list_break_on (const char *text, + const char *word, + const char *break_on, + enum type_code code) +{ + struct cleanup *back_to; + volatile struct gdb_exception except; + + return_val = NULL; + back_to = make_cleanup (do_free_completion_list, &return_val); + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + default_make_symbol_completion_list_break_on_1 (text, word, + break_on, code); + } + if (except.reason < 0) + { + if (except.error != MAX_COMPLETIONS_REACHED_ERROR) + throw_exception (except); + } + discard_cleanups (back_to); - return (return_val); + return return_val; } VEC (char_ptr) * diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp index 1123b99..f77bfe2 100644 --- a/gdb/testsuite/gdb.base/completion.exp +++ b/gdb/testsuite/gdb.base/completion.exp @@ -67,6 +67,7 @@ if ![runto_main] then { } set timeout 30 +gdb_test_no_output "set max-completions unlimited" gdb_test_no_output "complete print values\[0\].x." \ "field completion with invalid field" @@ -775,4 +776,86 @@ gdb_test_multiple "" "$test" { } } -return 0 +# +# Completion limiting. +# + +gdb_test_no_output "set max-completions 5" + +set test "command-name completion limiting using tab character" +send_gdb "p\t" +gdb_test_multiple "" "$test" { + -re "^p\\\x07$" { + send_gdb "\t" + gdb_test_multiple "" "$test" { + -re "List may be truncated, max-completions reached.*\r\n$gdb_prompt p$" { + # Complete the command and ignore the output to resync + # gdb for the next test. + send_gdb "\n" + gdb_test_multiple "" "$test" { + -re "$gdb_prompt $" { + pass "$test" + } + } + } + -re "$gdb_prompt p$" { + # Complete the command and ignore the output to resync + # gdb for the next test. + send_gdb "\n" + gdb_test_multiple "" "$test" { + -re "$gdb_prompt $" { + fail "$test" + } + } + } + } + } +} + +set test "command-name completion limiting using complete command" +send_gdb "complete p\n" +gdb_test_multiple "" "$test" { + -re "List may be truncated, max-completions reached.*\r\n$gdb_prompt $" { + pass "$test" + } +} + +gdb_test_no_output "set max-completions 3" + +set test "symbol-name completion limiting using tab character" +send_gdb "p marker\t" +gdb_test_multiple "" "$test" { + -re "^p marker\\\x07$" { + send_gdb "\t" + gdb_test_multiple "" "$test" { + -re "List may be truncated, max-completions reached.*\r\n$gdb_prompt p marker$" { + # Complete the command and ignore the output to resync + # gdb for the next test. + send_gdb "\n" + gdb_test_multiple "" "$test" { + -re "$gdb_prompt $" { + pass "$test" + } + } + } + -re "$gdb_prompt p marker$" { + # Complete the command and ignore the output to resync + # gdb for the next test. + send_gdb "\n" + gdb_test_multiple "" "$test" { + -re "$gdb_prompt $" { + fail "$test" + } + } + } + } + } +} + +set test "symbol-name completion limiting using complete command" +send_gdb "complete p mark\n" +gdb_test_multiple "" "$test" { + -re "List may be truncated, max-completions reached.*\r\n$gdb_prompt $" { + pass "$test" + } +} diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp index 322598e..019312c 100644 --- a/gdb/testsuite/gdb.linespec/ls-errs.exp +++ b/gdb/testsuite/gdb.linespec/ls-errs.exp @@ -26,6 +26,9 @@ if {[prepare_for_testing $testfile $exefile $srcfile \ # Turn off the pending breakpoint queries. gdb_test_no_output "set breakpoint pending off" +# Turn off completion limiting +gdb_test_no_output "set max-completions unlimited" + # We intentionally do not use gdb_breakpoint for these tests. # Break at 'linespec' and expect the message in ::error_messages indexed by diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c index bac76c3..e5cab45 100644 --- a/gdb/tui/tui-io.c +++ b/gdb/tui/tui-io.c @@ -132,6 +132,7 @@ static rl_getc_func_t *tui_old_rl_getc_function; static rl_voidfunc_t *tui_old_rl_redisplay_function; static rl_vintfunc_t *tui_old_rl_prep_terminal; static rl_voidfunc_t *tui_old_rl_deprep_terminal; +static rl_compdisp_func_t *tui_old_rl_display_matches_hook; static int tui_old_rl_echoing_p; /* Readline output stream. @@ -442,6 +443,7 @@ tui_setup_io (int mode) tui_old_rl_deprep_terminal = rl_deprep_term_function; tui_old_rl_prep_terminal = rl_prep_term_function; tui_old_rl_getc_function = rl_getc_function; + tui_old_rl_display_matches_hook = rl_completion_display_matches_hook; tui_old_rl_outstream = rl_outstream; tui_old_rl_echoing_p = _rl_echoing_p; rl_redisplay_function = tui_redisplay_readline; @@ -485,8 +487,8 @@ tui_setup_io (int mode) rl_deprep_term_function = tui_old_rl_deprep_terminal; rl_prep_term_function = tui_old_rl_prep_terminal; rl_getc_function = tui_old_rl_getc_function; + rl_completion_display_matches_hook = tui_old_rl_display_matches_hook; rl_outstream = tui_old_rl_outstream; - rl_completion_display_matches_hook = 0; _rl_echoing_p = tui_old_rl_echoing_p; rl_already_prompted = 0;