This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] PR gdb/17960 - Move completion_tracker_t into the completion API.


Keith Seitz <keiths@redhat.com> writes:
> The bug itself is easily demonstrated:
>
> $ gdb -nx -q gdb
> (gdb) b gdb.c:ma<TAB>
> ./../src/gdb/completer.c:837: internal-error: maybe_add_completion:
> Assertion `tracker != NULL' failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
> Quit this debugging session? (y or n)

Yeah.
Just didn't think of this case. Bleah.

High level thought.
A good next step after this patch would be to replace the "tracker"
argument we now pass around with a more general completion state
struct pointer.
Then we could, I think, get rid of the "return_val" global in symtab.c.
I haven't worked through the details so there may be some gotchas.
This doesn't have to be done as part of this patch, but OTOH now's
a good time to do this.

Further comments are prefixed with ====.

>
> This occurs because the code path in this case is:
> complete_line
> - complete_line_internal
> -- location_completer
> --- make_file_symbol_completion_list
> (...)
> ---- completion_list_add_name
> ----- maybe_add_completion
> ----> gdb_assert (tracker != NULL);
>
> The tracker in maybe_add_completion is a static global in symtab.c called
> completion_tracker.  It is initialized by
> default_make_symbol_completion_list_break_on_1 (which is a defaulted
> language vector method).  In this case, this function is never called
> and completion_tracker is left NULL/uninitialized.
>
> This patch refactors the completion API, adding a completion_tracker_t
> to the list of function arguments for all completion functions, removing
> the (file) global completion_tracker in symtab.c that is the cause of this bug.
>
> gdb/ChangeLog
>
> 	PR gdb/17960
> 	* cli/cli-decode.c (find_cmd): Use maybe_add_completion to
> 	implement completion tracking.
> 	* command.h (completer_ftype, completer_ftype_void,
> 	set_cmd_completer, set_cmd_completer_handle_brkchars,
> 	lookup_cmd, lookup_cmd_1, complete_on_cmdlist,
> 	complete_on_enum): Move to completer.h.
> 	* completer.c (location_completer): Use TRY_CATCH to catch
> 	max completion exception from make_file_symbol_completion_list,
> 	make_symbol_completion_list, and make_source_files_completion_list.
> 	(complete_line_internal): Empty the tracker when a unique
> 	command completion is found.
> 	(complete_line): Instantiate a new tracker earlier and pass this
> 	to complete_line_internal.
> 	If the list of completions is bigger than those tracked,
> 	completion tracking was not implemented for the requested completion;
> 	re-filter the list for maximum completions.  Otherwise simply
> 	copy the result.
> 	* completer.h (max_completions, new_completion_tracker,
> 	make_cleanup_free_completion_tracker, enum maybe_add_completion_enum,
> 	maybe_add_completion, throw_max_completions_reached_error): Move
> 	declarations to earlier in file.
> 	(completer_ftype, completer_ftype_void, set_cmd_completer,
> 	set_cmd_completer_handle_brkchars, lookup_cmd, lookup_cmd_1,
> 	complete_on_cmdlist, complete_on_enum): Move declarations here
> 	from command.h.
> 	* symtab.c (COMPLETION_LIST_ADD_SYMBOL,
> 	MCOMPLETION_LIST_ADD_SYMBOL): Add `tracker' as first argument.
> 	All users updated.
> 	(struct add_name_data): Add `tracker' member.
> 	(default_make_symbol_completion_list_break_on_1): Add tracker
> 	to call data.
> 	Do not instantiate a completion tracker here -- use the one
> 	passed instead.
> 	(add_filename_to_list): Implement completion tracking.
> 	(struct add_partial_filename_data): Add `tracker' member.
> 	(make_source_files_completion_list): Add tracker to call data.
> 	* symtab.h: Include completer.h.
> 	* ada-lang.c, breakpoint.c, cli/cli-cmds.c, cli/cli-decode.h,
> 	corefile.c, cp-abi.c, f-lang.c, infrun.c, interps.c, language.h,
> 	python/py-cmd.c, top.c, symtab.c: Updated for completion API change.

====

I've been told that regardless of the tediousness,
one line per file:

	* ada-lang.c: Updated for completion API change.
	* ... and so on.

You could instead just say "All callers updated."
at the relevant points.

>
> gdb/testsuite/ChangeLog
>
> 	PR gdb/17960
> 	* gdb.base/completion.exp: Add location completer tests.
> ---
>  gdb/ada-lang.c                        |    3 -
>  gdb/breakpoint.c                      |    6 +
>  gdb/cli/cli-cmds.c                    |    6 +
>  gdb/cli/cli-decode.c                  |   58 ++++++++---
>  gdb/cli/cli-decode.h                  |    1 
>  gdb/command.h                         |   31 ------
>  gdb/completer.c                       |  177 +++++++++++++++++++++++----------
>  gdb/completer.h                       |  168 +++++++++++++++++++------------
>  gdb/corefile.c                        |    3 -
>  gdb/cp-abi.c                          |    3 -
>  gdb/f-lang.c                          |    6 +
>  gdb/infrun.c                          |    5 +
>  gdb/interps.c                         |    1 
>  gdb/language.h                        |    3 -
>  gdb/python/py-cmd.c                   |    5 +
>  gdb/symtab.c                          |  166 ++++++++++++++++++-------------
>  gdb/symtab.h                          |   35 +++----
>  gdb/testsuite/gdb.base/completion.exp |   78 +++++++++++++++
>  gdb/top.c                             |    2 
>  19 files changed, 492 insertions(+), 265 deletions(-)
>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 562627a..161e3aa 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -6191,7 +6191,8 @@ ada_complete_symbol_matcher (const char *name, void *user_data)
>     the entire command on which completion is made.  */
>  
>  static VEC (char_ptr) *
> -ada_make_symbol_completion_list (const char *text0, const char *word,
> +ada_make_symbol_completion_list (completion_tracker_t tracker,
> +				 const char *text0, const char *word,
>  				 enum type_code code)
>  {
>    char *text;
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index a7cc6cb..2773f53 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -1020,6 +1020,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
>  
>  static VEC (char_ptr) *
>  condition_completer (struct cmd_list_element *cmd,
> +		     completion_tracker_t tracker,
>  		     const char *text, const char *word)
>  {
>    const char *space;
> @@ -1058,7 +1059,7 @@ condition_completer (struct cmd_list_element *cmd,
>  
>    /* We're completing the expression part.  */
>    text = skip_spaces_const (space);
> -  return expression_completer (cmd, text, word);
> +  return expression_completer (cmd, tracker, text, word);
>  }
>  
>  /* condition N EXP -- set break condition of breakpoint N to EXP.  */
> @@ -15393,11 +15394,12 @@ catching_syscall_number (int syscall_number)
>  /* Complete syscall names.  Used by "catch syscall".  */
>  static VEC (char_ptr) *
>  catch_syscall_completer (struct cmd_list_element *cmd,
> +			 completion_tracker_t tracker,
>                           const char *text, const char *word)
>  {
>    const char **list = get_syscall_names (get_current_arch ());
>    VEC (char_ptr) *retlist
> -    = (list == NULL) ? NULL : complete_on_enum (list, word, word);
> +    = (list == NULL) ? NULL : complete_on_enum (tracker, list, word, word);
>  
>    xfree (list);
>    return retlist;
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index e46f036..c2b4604 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -1344,7 +1344,7 @@ valid_command_p (const char *command)
>  {
>    struct cmd_list_element *c;
>  
> -  c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
> +  c = lookup_cmd_1 (NULL, &command, cmdlist, NULL, 1);
>  
>    if (c == NULL || c == (struct cmd_list_element *) -1)
>      return FALSE;
> @@ -1467,12 +1467,12 @@ alias_command (char *args, int from_tty)
>        alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
>        command_prefix = dyn_string_buf (command_prefix_dyn_string);
>  
> -      c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
> +      c_command = lookup_cmd_1 (NULL, &command_prefix, cmdlist, NULL, 1);
>        /* We've already tried to look up COMMAND.  */
>        gdb_assert (c_command != NULL
>  		  && c_command != (struct cmd_list_element *) -1);
>        gdb_assert (c_command->prefixlist != NULL);
> -      c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
> +      c_alias = lookup_cmd_1 (NULL, &alias_prefix, cmdlist, NULL, 1);
>        if (c_alias != c_command)
>  	error (_("ALIAS and COMMAND prefixes do not match."));
>  
> diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
> index 4ec6ec0..b31772c 100644
> --- a/gdb/cli/cli-decode.c
> +++ b/gdb/cli/cli-decode.c
> @@ -35,7 +35,8 @@ static struct cmd_list_element *delete_cmd (const char *name,
>  					    struct cmd_list_element **posthook,
>  					    struct cmd_list_element **posthookee);
>  
> -static struct cmd_list_element *find_cmd (const char *command,
> +static struct cmd_list_element *find_cmd (completion_tracker_t tracker,
> +					  const char *command,
>  					  int len,
>  					  struct cmd_list_element *clist,
>  					  int ignore_help_classes,
> @@ -649,6 +650,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class class,
>  
>  static VEC (char_ptr) *
>  integer_unlimited_completer (struct cmd_list_element *ignore,
> +			     completion_tracker_t tracker,
>  			     const char *text, const char *word)
>  {
>    static const char * const keywords[] =
> @@ -657,7 +659,7 @@ integer_unlimited_completer (struct cmd_list_element *ignore,
>        NULL,
>      };
>  
> -  return complete_on_enum (keywords, text, word);
> +  return complete_on_enum (tracker, keywords, text, word);
>  }
>  
>  /* Add element named NAME to both the set and show command LISTs (the
> @@ -1215,22 +1217,43 @@ help_cmd_list (struct cmd_list_element *list, enum command_class class,
>     found in nfound.  */
>  
>  static struct cmd_list_element *
> -find_cmd (const char *command, int len, struct cmd_list_element *clist,
> +find_cmd (completion_tracker_t tracker,
> +	  const char *command, int len, struct cmd_list_element *clist,
>  	  int ignore_help_classes, int *nfound)
>  {
>    struct cmd_list_element *found, *c;
> +  int max_reached;
>  
>    found = (struct cmd_list_element *) NULL;
>    *nfound = 0;
> -  for (c = clist; c; c = c->next)
> +  for (c = clist, max_reached = 0; c; c = c->next)
>      if (!strncmp (command, c->name, len)
>  	&& (!ignore_help_classes || c->func))
>        {
> -	found = c;
> -	(*nfound)++;
> -	if (c->name[len] == '\0')
> +	enum maybe_add_completion_enum add_status;
> +
> +	add_status = (tracker == NULL
> +		      ? MAYBE_ADD_COMPLETION_OK
> +		      : maybe_add_completion (tracker, c->name));
> +	switch (add_status)
>  	  {
> -	    *nfound = 1;
> +	  case MAYBE_ADD_COMPLETION_OK:
> +	    found = c;
> +	    (*nfound)++;
> +	    if (c->name[len] == '\0')
> +	      {
> +		*nfound = 1;
> +		return found;
> +	      }
> +	    break;
> +	  case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> +	    found = c;
> +	    (*nfound)++;
> +	    return found;
> +	  case MAYBE_ADD_COMPLETION_MAX_REACHED:
> +	    return found;
> +	  case MAYBE_ADD_COMPLETION_DUPLICATE:
> +	    continue;
>  	    break;
>  	  }
>        }
> @@ -1336,7 +1359,8 @@ valid_user_defined_cmd_name_p (const char *name)
>     the struct cmd_list_element is NULL).  */
>  
>  struct cmd_list_element *
> -lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> +lookup_cmd_1 (completion_tracker_t tracker,
> +	      const char **text, struct cmd_list_element *clist,
>  	      struct cmd_list_element **result_list, int ignore_help_classes)
>  {
>    char *command;
> @@ -1365,7 +1389,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
>    /* Look it up.  */
>    found = 0;
>    nfound = 0;
> -  found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
> +  found = find_cmd (tracker, command, len, clist, ignore_help_classes,
> +		    &nfound);
>  
>    /* We didn't find the command in the entered case, so lower case it
>       and search again.  */
> @@ -1377,7 +1402,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
>  
>  	  command[tmp] = isupper (x) ? tolower (x) : x;
>  	}
> -      found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
> +      found = find_cmd (tracker, command, len, clist, ignore_help_classes,
> +			&nfound);
>      }
>  
>    /* If nothing matches, we have a simple failure.  */
> @@ -1414,7 +1440,7 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
>  
>    if (found->prefixlist)
>      {
> -      c = lookup_cmd_1 (text, *found->prefixlist, result_list,
> +      c = lookup_cmd_1 (tracker, text, *found->prefixlist, result_list,
>  			ignore_help_classes);
>        if (!c)
>  	{
> @@ -1491,7 +1517,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list, char *cmdtype,
>    if (!*line)
>      error (_("Lack of needed %scommand"), cmdtype);
>  
> -  c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
> +  c = lookup_cmd_1 (NULL, line, list, &last_list, ignore_help_classes);
>  
>    if (!c)
>      {
> @@ -1718,7 +1744,7 @@ lookup_cmd_composition (const char *text,
>        /* Look it up.  */
>        *cmd = 0;
>        nfound = 0;
> -      *cmd = find_cmd (command, len, cur_list, 1, &nfound);
> +      *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
>        
>        /* We didn't find the command in the entered case, so lower case
>  	 it and search again.
> @@ -1731,7 +1757,7 @@ lookup_cmd_composition (const char *text,
>  
>  	      command[tmp] = isupper (x) ? tolower (x) : x;
>  	    }
> -	  *cmd = find_cmd (command, len, cur_list, 1, &nfound);
> +	  *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
>  	}
>        
>        if (*cmd == CMD_LIST_AMBIGUOUS)
> @@ -1842,7 +1868,7 @@ complete_on_cmdlist (struct cmd_list_element *list,
>     "oobar"; if WORD is "baz/foo", return "baz/foobar".  */
>  
>  VEC (char_ptr) *
> -complete_on_enum (const char *const *enumlist,
> +complete_on_enum (completion_tracker_t ignore, const char *const *enumlist,
>  		  const char *text, const char *word)
>  {
>    VEC (char_ptr) *matchlist = NULL;
> diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
> index ec89325..bbedb52 100644
> --- a/gdb/cli/cli-decode.h
> +++ b/gdb/cli/cli-decode.h
> @@ -23,6 +23,7 @@
>  
>  /* Include the public interfaces.  */
>  #include "command.h"
> +#include "completer.h"
>  
>  struct re_pattern_buffer;
>  
> diff --git a/gdb/command.h b/gdb/command.h
> index 956eeaa..35d61bd 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -156,19 +156,6 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty,
>  extern void set_cmd_sfunc (struct cmd_list_element *cmd,
>  			   cmd_sfunc_ftype *sfunc);
>  
> -typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
> -					 const char *, const char *);
> -
> -typedef void completer_ftype_void (struct cmd_list_element *,
> -				   const char *, const char *);
> -
> -extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
> -
> -/* Set the completer_handle_brkchars callback.  */
> -
> -extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
> -					       completer_ftype_void *);
> -
>  /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
>     around in cmd objects to test the value of the commands sfunc().  */
>  extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
> @@ -189,18 +176,6 @@ extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
>  /* Return the type of the command.  */
>  extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
>  
> -/* Flag for an ambiguous cmd_list result.  */
> -#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
> -
> -extern struct cmd_list_element *lookup_cmd (const char **,
> -					    struct cmd_list_element *, char *,
> -					    int, int);
> -

====

Seems odd to remove CMD_LIST_AMBIGUOUS, lookup_cmd, lookup_cmd_1 here.
Can we keep them here, at least for now?
I can imagine the motivation is an inclusion order issue.
If we passed around struct completion_state instead of completion_tracker_t
then we could just forward declare it in command.h.
Another way, of course, if one wanted to just pass tracker, is to change the
type to struct completion_tracker and forward declare that in command.h.

> -extern struct cmd_list_element *lookup_cmd_1 (const char **,
> -					      struct cmd_list_element *,
> -					      struct cmd_list_element **,
> -					      int);
> -
>  extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
>  					       const char * );
>  
> @@ -225,12 +200,6 @@ extern struct cmd_list_element *add_info (const char *,
>  extern struct cmd_list_element *add_info_alias (const char *, const char *,
>  						int);
>  
> -extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
> -					    const char *, const char *, int);
> -
> -extern VEC (char_ptr) *complete_on_enum (const char *const *enumlist,
> -					 const char *, const char *);
> -
>  /* Functions that implement commands about CLI commands.  */
>  
>  extern void help_list (struct cmd_list_element *, const char *,
> diff --git a/gdb/completer.c b/gdb/completer.c
> index add79cc..67644d1 100644
> --- a/gdb/completer.c
> +++ b/gdb/completer.c
> @@ -107,7 +107,8 @@ readline_line_completion_function (const char *text, int matches)
>  /* This can be used for functions which don't want to complete on
>     symbols but don't want to complete on anything else either.  */
>  VEC (char_ptr) *
> -noop_completer (struct cmd_list_element *ignore, 
> +noop_completer (struct cmd_list_element *ignore,
> +		completion_tracker_t ignore2,
>  		const char *text, const char *prefix)
>  {
>    return NULL;
> @@ -115,7 +116,8 @@ noop_completer (struct cmd_list_element *ignore,
>  
>  /* Complete on filenames.  */
>  VEC (char_ptr) *
> -filename_completer (struct cmd_list_element *ignore, 
> +filename_completer (struct cmd_list_element *ignore,
> +		    completion_tracker_t ignore2,
>  		    const char *text, const char *word)
>  {
>    int subsequent_name;
> @@ -184,7 +186,8 @@ filename_completer (struct cmd_list_element *ignore,
>     etc.  */
>  
>  VEC (char_ptr) *
> -location_completer (struct cmd_list_element *ignore, 
> +location_completer (struct cmd_list_element *ignore,
> +		    completion_tracker_t tracker,
>  		    const char *text, const char *word)
>  {
>    int n_syms, n_files, ix;
> @@ -260,18 +263,41 @@ location_completer (struct cmd_list_element *ignore,
>       symbols as well as on files.  */
>    if (colon)
>      {
> -      list = make_file_symbol_completion_list (symbol_start, word,
> -					       file_to_match);
> +      struct gdb_exception e;
> +
> +      TRY_CATCH (e, RETURN_MASK_ERROR)
> +	{
> +	  list = make_file_symbol_completion_list (tracker, symbol_start,
> +						   word, file_to_match);
> +	}

====

Why is this now wrapped in a try/catch?
And similarly below.
Is it because MAX_COMPLETIONS_REACHED_ERROR may be thrown?
I'd expect make_file_symbol_completion_list to catch it
and return the list collected thus far.

> +      if (e.reason < 0)
> +	list = NULL;
>        xfree (file_to_match);
>      }
>    else
>      {
> -      list = make_symbol_completion_list (symbol_start, word);
> +      struct gdb_exception e;
> +
> +      TRY_CATCH (e, RETURN_MASK_ERROR)
> +	{
> +	  list = make_symbol_completion_list (tracker, symbol_start, word);
> +	}
> +      if (e.reason < 0)
> +	list = NULL;
> +
>        /* If text includes characters which cannot appear in a file
>  	 name, they cannot be asking for completion on files.  */
>        if (strcspn (text, 
>  		   gdb_completer_file_name_break_characters) == text_len)
> -	fn_list = make_source_files_completion_list (text, text);
> +	{
> +	  TRY_CATCH (e, RETURN_MASK_ERROR)
> +	    {
> +	      fn_list = make_source_files_completion_list (tracker, text,
> +							   text);
> +	    }
> +	  if (e.reason < 0)
> +	    fn_list = NULL;
> +	}
>      }
>  
>    n_syms = VEC_length (char_ptr, list);
> @@ -326,7 +352,14 @@ location_completer (struct cmd_list_element *ignore,
>      {
>        /* No completions at all.  As the final resort, try completing
>  	 on the entire text as a symbol.  */
> -      list = make_symbol_completion_list (orig_text, word);
> +      struct gdb_exception e;
> +
> +      TRY_CATCH (e, RETURN_MASK_ERROR)
> +	{
> +	  list = make_symbol_completion_list (tracker, orig_text, word);
> +	}
> +      if (e.reason < 0)
> +	list = NULL;
>      }
>  
>    return list;
> @@ -389,7 +422,8 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
>     names, but some language parsers also have support for completing
>     field names.  */
>  VEC (char_ptr) *
> -expression_completer (struct cmd_list_element *ignore, 
> +expression_completer (struct cmd_list_element *ignore,
> +		      completion_tracker_t tracker,
>  		      const char *text, const char *word)
>  {
>    struct type *type = NULL;
> @@ -434,7 +468,8 @@ expression_completer (struct cmd_list_element *ignore,
>        VEC (char_ptr) *result;
>        struct cleanup *cleanup = make_cleanup (xfree, fieldname);
>  
> -      result = make_symbol_completion_type (fieldname, fieldname, code);
> +      result = make_symbol_completion_type (tracker, fieldname, fieldname,
> +					    code);
>        do_cleanups (cleanup);
>        return result;
>      }
> @@ -448,7 +483,7 @@ expression_completer (struct cmd_list_element *ignore,
>      ;
>  
>    /* Not ideal but it is what we used to do before...  */
> -  return location_completer (ignore, p, word);
> +  return location_completer (ignore, tracker, p, word);
>  }
>  
>  /* See definition in completer.h.  */
> @@ -526,7 +561,7 @@ complete_line_internal_reason;
>   */
>  
>  static VEC (char_ptr) *
> -complete_line_internal (const char *text, 
> +complete_line_internal (completion_tracker_t tracker, const char *text,
>  			const char *line_buffer, int point,
>  			complete_line_internal_reason reason)
>  {
> @@ -572,7 +607,21 @@ complete_line_internal (const char *text,
>      }
>    else
>      {
> -      c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
> +      /* There are two possible scenarios:
> +	 1) The user is searching for completions to a command
> +	 2) The user is attempting to complete the argument of
> +	    a specific command.
> +
> +	In either case, lookup_cmd_1 will increment the tracker.
> +	However, for case #2, the tracker's results must be cleared,
> +	since we don't want the actual command lookup to be counted
> +	by that command's completer function.  If we didn't do this,
> +	we'd end up with an off-by-one error between the tracker
> +	and the returned completion list.  */
> +      c = lookup_cmd_1 (tracker, &p, cmdlist, &result_list,
> +			ignore_help_classes);
> +      if (c != CMD_LIST_AMBIGUOUS && tracker != NULL)
> +	htab_empty (tracker);
>      }
>  
>    /* Move p up to the next interesting thing.  */
> @@ -658,7 +707,7 @@ complete_line_internal (const char *text,
>  	      else if (c->enums)
>  		{
>  		  if (reason != handle_brkchars)
> -		    list = complete_on_enum (c->enums, p, word);
> +		    list = complete_on_enum (tracker, c->enums, p, word);
>  		  rl_completer_word_break_characters =
>  		    gdb_completer_command_word_break_characters;
>  		}
> @@ -698,7 +747,7 @@ complete_line_internal (const char *text,
>  		      && c->completer_handle_brkchars != NULL)
>  		    (*c->completer_handle_brkchars) (c, p, word);
>  		  if (reason != handle_brkchars && c->completer != NULL)
> -		    list = (*c->completer) (c, p, word);
> +		    list = (*c->completer) (c, tracker, p, word);
>  		}
>  	    }
>  	  else
> @@ -744,7 +793,7 @@ complete_line_internal (const char *text,
>  	  else if (c->enums)
>  	    {
>  	      if (reason != handle_brkchars)
> -		list = complete_on_enum (c->enums, p, word);
> +		list = complete_on_enum (tracker, c->enums, p, word);
>  	    }
>  	  else
>  	    {
> @@ -774,7 +823,7 @@ complete_line_internal (const char *text,
>  		  && c->completer_handle_brkchars != NULL)
>  		(*c->completer_handle_brkchars) (c, p, word);
>  	      if (reason != handle_brkchars && c->completer != NULL)
> -		list = (*c->completer) (c, p, word);
> +		list = (*c->completer) (c, tracker, p, word);
>  	    }
>  	}
>      }
> @@ -825,7 +874,7 @@ make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
>  /* See completer.h.  */
>  
>  enum maybe_add_completion_enum
> -maybe_add_completion (completion_tracker_t tracker, char *name)
> +maybe_add_completion (completion_tracker_t tracker, const char *name)
>  {
>    void **slot;
>  
> @@ -844,7 +893,7 @@ maybe_add_completion (completion_tracker_t tracker, char *name)
>    if (*slot != HTAB_EMPTY_ENTRY)
>      return MAYBE_ADD_COMPLETION_DUPLICATE;
>  
> -  *slot = name;
> +  *slot = (void *) name;
>  
>    return (htab_elements (tracker) < max_completions
>  	  ? MAYBE_ADD_COMPLETION_OK
> @@ -875,52 +924,75 @@ complete_line (const char *text, const char *line_buffer, int point)
>  {
>    VEC (char_ptr) *list;
>    VEC (char_ptr) *result = NULL;
> -  struct cleanup *cleanups;
> +  struct cleanup *tracker_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.  */
> +  list = complete_line_internal (tracker, text, line_buffer, point,
> +				 handle_completions);
>  
> -  for (ix = 0, max_reached = 0;
> -       !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
> -       ++ix)
> +  if (max_completions < 0)
>      {
> -      enum maybe_add_completion_enum add_status;
> +      do_cleanups (cleanups);
> +      return list;
> +    }
> +
> +  make_cleanup_free_char_ptr_vec (list);
> +
> +  /* If complete_line_internal returned more completions than were
> +     recorded by the completion tracker, then the completer function that
> +     was run does not support completion tracking.  In this case,
> +     do a final test for too many completions.
>  
> -      add_status = maybe_add_completion (tracker, candidate);
> +     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.  */
>  
> -      switch (add_status)
> +  if (VEC_length (char_ptr, list) > htab_elements (tracker))
> +    {
> +      /* Clear the tracker so that we can re-use it to count the number
> +	 of returned completions.  */
> +      htab_empty (tracker);
> +
> +      for (ix = 0, max_reached = 0;
> +	   !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
> +	   ++ix)
>  	{
> -	  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;
> +	  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;
> +	    }
>  	}
>      }
> +  else
> +    {
> +      /* There is a valid tracker for the completion -- simply copy
> +	 the returned list into the return result.  */
> +      for (ix = 0; VEC_iterate (char_ptr, list, ix, candidate); ++ix)
> +	VEC_safe_push (char_ptr, result, xstrdup (candidate));

====

Can we just return list instead of making a copy of it?

E.g.,

  if (VEC_length (char_ptr, list) <= htab_elements (tracker))
    {
      discard_cleanups (list_cleanups);
      do_cleanups (cleanups);
      return list;
    }

  /* Clear the tracker so that we can re-use it to count the number
     of returned completions.  */
  ...

> +    }
>  
>    do_cleanups (cleanups);
>  
> @@ -929,10 +1001,11 @@ complete_line (const char *text, const char *line_buffer, int point)
>  
>  /* Complete on command names.  Used by "help".  */
>  VEC (char_ptr) *
> -command_completer (struct cmd_list_element *ignore, 
> +command_completer (struct cmd_list_element *ignore,
> +		   completion_tracker_t tracker,
>  		   const char *text, const char *word)
>  {
> -  return complete_line_internal (word, text, 
> +  return complete_line_internal (tracker, word, text,
>  				 strlen (text), handle_help);
>  }
>  
> @@ -940,6 +1013,7 @@ command_completer (struct cmd_list_element *ignore,
>  
>  VEC (char_ptr) *
>  signal_completer (struct cmd_list_element *ignore,
> +		  completion_tracker_t ignore2,
>  		  const char *text, const char *word)
>  {
>    VEC (char_ptr) *return_val = NULL;
> @@ -970,6 +1044,7 @@ signal_completer (struct cmd_list_element *ignore,
>  
>  VEC (char_ptr) *
>  reg_or_group_completer (struct cmd_list_element *ignore,
> +			completion_tracker_t ingore2,
>  			const char *text, const char *word)
>  {
>    VEC (char_ptr) *result = NULL;
> @@ -1013,7 +1088,7 @@ gdb_completion_word_break_characters (void)
>  {
>    VEC (char_ptr) *list;
>  
> -  list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point,
> +  list = complete_line_internal (NULL, rl_line_buffer, rl_line_buffer, rl_point,
>  				 handle_brkchars);
>    gdb_assert (list == NULL);
>    return rl_completer_word_break_characters;
> diff --git a/gdb/completer.h b/gdb/completer.h
> index 56e1a2b..7bc0543 100644
> --- a/gdb/completer.h
> +++ b/gdb/completer.h
> @@ -18,7 +18,6 @@
>  #define COMPLETER_H 1
>  
>  #include "gdb_vecs.h"
> -#include "command.h"
>  
>  /* Types of functions in struct match_list_displayer.  */
>  
> @@ -33,6 +32,70 @@ typedef void mld_erase_entire_line_ftype (const struct match_list_displayer *);
>  typedef void mld_beep_ftype (const struct match_list_displayer *);
>  typedef int mld_read_key_ftype (const struct match_list_displayer *);
>  
> +/* 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, const char *name);
> +
> +/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR.  */
> +
> +extern void throw_max_completions_reached_error (void);
> +
>  /* Interface between CLI/TUI and gdb_match_list_displayer.  */
>  
>  struct match_list_displayer
> @@ -76,106 +139,83 @@ extern char *readline_line_completion_function (const char *text,
>  						int matches);
>  
>  extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
> +				       completion_tracker_t,
>  				       const char *, const char *);
>  
>  extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
> +					   completion_tracker_t,
>  					   const char *, const char *);
>  
>  extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
> +					     completion_tracker_t,
>  					     const char *, const char *);
>  
>  extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
> +					   completion_tracker_t,
>  					   const char *, const char *);
>  
>  extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
> +					  completion_tracker_t,
>  					  const char *, const char *);
>  
>  extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
> +					 completion_tracker_t,
>  					 const char *, const char *);
>  
>  extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
> +					       completion_tracker_t,
>  					       const char *, const char *);
>  
>  extern char *get_gdb_completer_quote_characters (void);
>  
>  extern char *gdb_completion_word_break_characters (void);
>  
> -/* Set the word break characters array to the corresponding set of
> -   chars, based on FN.  This function is useful for cases when the
> -   completer doesn't know the type of the completion until some
> -   calculation is done (e.g., for Python functions).  */
> -
> -extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
> -
> -/* Exported to linespec.c */
> -
> -extern const char *skip_quoted_chars (const char *, 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 VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
> +					 completion_tracker_t,
> +					 const char *, const char *);
>  
> -typedef htab_t completion_tracker_t;
> +typedef void completer_ftype_void (struct cmd_list_element *,
> +				   const char *, const char *);
>  
> -/* 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 void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
>  
> -extern completion_tracker_t new_completion_tracker (void);
> +/* Set the completer_handle_brkchars callback.  */
>  
> -/* Make a cleanup to free a completion tracker, and reset its pointer
> -   to NULL.  */
> +extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
> +					       completer_ftype_void *);
>  
> -extern struct cleanup *make_cleanup_free_completion_tracker
> -		      (completion_tracker_t *tracker_ptr);
> -
> -/* Return values for maybe_add_completion.  */
> +/* Set the word break characters array to the corresponding set of
> +   chars, based on FN.  This function is useful for cases when the
> +   completer doesn't know the type of the completion until some
> +   calculation is done (e.g., for Python functions).  */
>  
> -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,
> +extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
>  
> -  /* NAME has been recorded and max_completions has been reached
> -     (thus the caller can stop searching).  */
> -  MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
> +extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
> +					    const char *, const char *, int);
>  
> -  /* max-completions entries has been reached.
> -     Whether NAME is a duplicate or not is not determined.  */
> -  MAYBE_ADD_COMPLETION_MAX_REACHED,
> +extern VEC (char_ptr) *complete_on_enum (completion_tracker_t,
> +					 const char *const *enumlist,
> +					 const char *, const char *);
>  
> -  /* NAME has already been recorded.
> -     Note that this is never returned if completion tracking is disabled
> -     (max_completions < 0).  */
> -  MAYBE_ADD_COMPLETION_DUPLICATE
> -};
> +/* Flag for an ambiguous cmd_list result.  */
> +#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
>  
> -/* 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.
> +extern struct cmd_list_element *lookup_cmd (const char **,
> +					    struct cmd_list_element *, char *,
> +					    int, int);
>  
> -   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 struct cmd_list_element *lookup_cmd_1 (completion_tracker_t,
> +					      const char **,
> +					      struct cmd_list_element *,
> +					      struct cmd_list_element **,
> +					      int);
>  
> -extern enum maybe_add_completion_enum
> -  maybe_add_completion (completion_tracker_t tracker, char *name);
> +/* Exported to linespec.c */
>  
> -/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR.  */ 
> +extern const char *skip_quoted_chars (const char *, const char *,
> +				      const char *);
>  
> -extern void throw_max_completions_reached_error (void);
> +extern const char *skip_quoted (const char *);
>  
>  #endif /* defined (COMPLETER_H) */
> diff --git a/gdb/corefile.c b/gdb/corefile.c
> index a042e6d..309a93d 100644
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
> @@ -469,6 +469,7 @@ set_gnutarget_command (char *ignore, int from_tty,
>  
>  static VEC (char_ptr) *
>  complete_set_gnutarget (struct cmd_list_element *cmd,
> +			completion_tracker_t tracker,
>  			const char *text, const char *word)
>  {
>    static const char **bfd_targets;
> @@ -486,7 +487,7 @@ complete_set_gnutarget (struct cmd_list_element *cmd,
>        bfd_targets[last + 1] = NULL;
>      }
>  
> -  return complete_on_enum (bfd_targets, text, word);
> +  return complete_on_enum (tracker, bfd_targets, text, word);
>  }
>  
>  /* Set the gnutarget.  */
> diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c
> index 9316c4c..4086d0c 100644
> --- a/gdb/cp-abi.c
> +++ b/gdb/cp-abi.c
> @@ -355,6 +355,7 @@ set_cp_abi_cmd (char *args, int from_tty)
>  
>  static VEC (char_ptr) *
>  cp_abi_completer (struct cmd_list_element *ignore,
> +		  completion_tracker_t tracker,
>  		  const char *text, const char *word)
>  {
>    static const char **cp_abi_names;
> @@ -369,7 +370,7 @@ cp_abi_completer (struct cmd_list_element *ignore,
>        cp_abi_names[i] = NULL;
>      }
>  
> -  return complete_on_enum (cp_abi_names, text, word);
> +  return complete_on_enum (tracker, cp_abi_names, text, word);
>  }
>  
>  /* Show the currently selected C++ ABI.  */
> diff --git a/gdb/f-lang.c b/gdb/f-lang.c
> index 8b61028..d772cfa 100644
> --- a/gdb/f-lang.c
> +++ b/gdb/f-lang.c
> @@ -229,10 +229,12 @@ f_word_break_characters (void)
>     class.  */
>  
>  static VEC (char_ptr) *
> -f_make_symbol_completion_list (const char *text, const char *word,
> +f_make_symbol_completion_list (completion_tracker_t tracker,
> +			       const char *text, const char *word,
>  			       enum type_code code)
>  {
> -  return default_make_symbol_completion_list_break_on (text, word, ":", code);
> +  return default_make_symbol_completion_list_break_on (tracker, text, word,
> +						       ":", code);
>  }
>  
>  const struct language_defn f_language_defn =
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 15589b6..75fe2e3 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6934,6 +6934,7 @@ Are you sure you want to change it? "),
>  
>  static VEC (char_ptr) *
>  handle_completer (struct cmd_list_element *ignore,
> +		  completion_tracker_t tracker,
>  		  const char *text, const char *word)
>  {
>    VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
> @@ -6951,8 +6952,8 @@ handle_completer (struct cmd_list_element *ignore,
>        NULL,
>      };
>  
> -  vec_signals = signal_completer (ignore, text, word);
> -  vec_keywords = complete_on_enum (keywords, word, word);
> +  vec_signals = signal_completer (ignore, tracker, text, word);
> +  vec_keywords = complete_on_enum (tracker, keywords, word, word);
>  
>    return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
>    VEC_free (char_ptr, vec_signals);
> diff --git a/gdb/interps.c b/gdb/interps.c
> index 90b5b2d..2215ac1 100644
> --- a/gdb/interps.c
> +++ b/gdb/interps.c
> @@ -438,6 +438,7 @@ interpreter_exec_cmd (char *args, int from_tty)
>  /* List the possible interpreters which could complete the given text.  */
>  static VEC (char_ptr) *
>  interpreter_completer (struct cmd_list_element *ignore,
> +		       completion_tracker_t ingore2,
>  		       const char *text, const char *word)
>  {
>    int textlen;
> diff --git a/gdb/language.h b/gdb/language.h
> index 436fd6e..b095093 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -301,7 +301,8 @@ struct language_defn
>         completion is being made.  If CODE is TYPE_CODE_UNDEF, then all
>         symbols should be examined; otherwise, only STRUCT_DOMAIN
>         symbols whose type has a code of CODE should be matched.  */
> -    VEC (char_ptr) *(*la_make_symbol_completion_list) (const char *text,
> +    VEC (char_ptr) *(*la_make_symbol_completion_list) (completion_tracker_t,
> +						       const char *text,
>  						       const char *word,
>  						       enum type_code code);
>  
> diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
> index a5e96d6..2f95b46 100644
> --- a/gdb/python/py-cmd.c
> +++ b/gdb/python/py-cmd.c
> @@ -347,6 +347,7 @@ cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
>  
>  static VEC (char_ptr) *
>  cmdpy_completer (struct cmd_list_element *command,
> +		 completion_tracker_t tracker,
>  		 const char *text, const char *word)
>  {
>    PyObject *resultobj = NULL;
> @@ -378,7 +379,7 @@ cmdpy_completer (struct cmd_list_element *command,
>  	  PyErr_Clear ();
>  	}
>        else if (value >= 0 && value < (long) N_COMPLETERS)
> -	result = completers[value].completer (command, text, word);
> +	result = completers[value].completer (command, tracker, text, word);
>      }
>    else
>      {
> @@ -485,7 +486,7 @@ gdbpy_parse_command_name (const char *name,
>    prefix_text[i + 1] = '\0';
>  
>    prefix_text2 = prefix_text;
> -  elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
> +  elt = lookup_cmd_1 (NULL, &prefix_text2, *start_list, NULL, 1);
>    if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
>      {
>        PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 5302afa..9f04966 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -4994,29 +4994,21 @@ do_free_completion_list (void *list)
>  
>  static VEC (char_ptr) *return_val;
>  
> -#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
> -      completion_list_add_name \
> -	(SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
> +#define COMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
> +  completion_list_add_name \
> +    (tracker, SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
>  
> -#define MCOMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
> -      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;
> +#define MCOMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
> +  completion_list_add_name \
> +    ((tracker), MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
>  
>  /*  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.  */
>  
>  static void
> -completion_list_add_name (const char *symname,
> +completion_list_add_name (completion_tracker_t tracker,
> +			  const char *symname,
>  			  const char *sym_text, int sym_text_len,
>  			  const char *text, const char *word)
>  {
> @@ -5051,7 +5043,7 @@ completion_list_add_name (const char *symname,
>  	strcat (new, symname);
>        }
>  
> -    add_status = maybe_add_completion (completion_tracker, new);
> +    add_status = maybe_add_completion (tracker, new);
>  
>      switch (add_status)
>        {
> @@ -5075,7 +5067,8 @@ completion_list_add_name (const char *symname,
>     again and feed all the selectors into the mill.  */
>  
>  static void
> -completion_list_objc_symbol (struct minimal_symbol *msymbol,
> +completion_list_objc_symbol (completion_tracker_t tracker,
> +			     struct minimal_symbol *msymbol,
>  			     const char *sym_text, int sym_text_len,
>  			     const char *text, const char *word)
>  {
> @@ -5093,7 +5086,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
>  
>    if (sym_text[0] == '[')
>      /* Complete on shortened method method.  */
> -    completion_list_add_name (method + 1, sym_text, sym_text_len, text, word);
> +    completion_list_add_name (tracker, method + 1, sym_text, sym_text_len,
> +			      text, word);
>  
>    while ((strlen (method) + 1) >= tmplen)
>      {
> @@ -5114,9 +5108,11 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
>        memcpy (tmp, method, (category - method));
>        tmp[category - method] = ' ';
>        memcpy (tmp + (category - method) + 1, selector, strlen (selector) + 1);
> -      completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
> +      completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
> +				word);
>        if (sym_text[0] == '[')
> -	completion_list_add_name (tmp + 1, sym_text, sym_text_len, text, word);
> +	completion_list_add_name (tracker, tmp + 1, sym_text, sym_text_len,
> +				  text, word);
>      }
>  
>    if (selector != NULL)
> @@ -5127,7 +5123,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
>        if (tmp2 != NULL)
>  	*tmp2 = '\0';
>  
> -      completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
> +      completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
> +				word);
>      }
>  }
>  
> @@ -5178,9 +5175,9 @@ language_search_unquoted_string (const char *text, const char *p)
>  }
>  
>  static void
> -completion_list_add_fields (struct symbol *sym, const char *sym_text,
> -			    int sym_text_len, const char *text,
> -			    const char *word)
> +completion_list_add_fields (completion_tracker_t tracker, struct symbol *sym,
> +			    const char *sym_text, int sym_text_len,
> +			    const char *text, const char *word)
>  {
>    if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
>      {
> @@ -5191,7 +5188,7 @@ completion_list_add_fields (struct symbol *sym, const char *sym_text,
>        if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
>  	for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
>  	  if (TYPE_FIELD_NAME (t, j))
> -	    completion_list_add_name (TYPE_FIELD_NAME (t, j),
> +	    completion_list_add_name (tracker, TYPE_FIELD_NAME (t, j),
>  				      sym_text, sym_text_len, text, word);
>      }
>  }
> @@ -5206,6 +5203,7 @@ struct add_name_data
>    int sym_text_len;
>    const char *text;
>    const char *word;
> +  completion_tracker_t tracker;
>  
>    /* Extra argument required for add_symtab_completions.  */
>    enum type_code code;
> @@ -5221,7 +5219,7 @@ add_macro_name (const char *name, const struct macro_definition *ignore,
>  {
>    struct add_name_data *datum = (struct add_name_data *) user_data;
>  
> -  completion_list_add_name (name,
> +  completion_list_add_name (datum->tracker, name,
>  			    datum->sym_text, datum->sym_text_len,
>  			    datum->text, datum->word);
>  }
> @@ -5240,6 +5238,7 @@ symbol_completion_matcher (const char *name, void *user_data)
>  
>  static void
>  add_symtab_completions (struct compunit_symtab *cust,
> +			completion_tracker_t tracker,
>  			const char *sym_text, int sym_text_len,
>  			const char *text, const char *word,
>  			enum type_code code)
> @@ -5258,7 +5257,7 @@ add_symtab_completions (struct compunit_symtab *cust,
>  	  if (code == TYPE_CODE_UNDEF
>  	      || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
>  		  && TYPE_CODE (SYMBOL_TYPE (sym)) == code))
> -	    COMPLETION_LIST_ADD_SYMBOL (sym,
> +	    COMPLETION_LIST_ADD_SYMBOL (tracker, sym,
>  					sym_text, sym_text_len,
>  					text, word);
>  	}
> @@ -5274,14 +5273,15 @@ symtab_expansion_callback (struct compunit_symtab *symtab,
>  {
>    struct add_name_data *datum = (struct add_name_data *) user_data;
>  
> -  add_symtab_completions (symtab,
> +  add_symtab_completions (symtab, datum->tracker,
>  			  datum->sym_text, datum->sym_text_len,
>  			  datum->text, datum->word,
>  			  datum->code);
>  }
>  
>  static void
> -default_make_symbol_completion_list_break_on_1 (const char *text,
> +default_make_symbol_completion_list_break_on_1 (completion_tracker_t tracker,
> +						const char *text,
>  						const char *word,
>  						const char *break_on,
>  						enum type_code code)
> @@ -5302,7 +5302,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>    /* Length of sym_text.  */
>    int sym_text_len;
>    struct add_name_data datum;
> -  struct cleanup *cleanups;
>  
>    /* Now look for the symbol we are supposed to complete on.  */
>    {
> @@ -5373,14 +5372,12 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>      }
>    gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '(');
>  
> -  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;
>    datum.text = text;
>    datum.word = word;
>    datum.code = code;
> +  datum.tracker = tracker;
>  
>    /* At this point scan through the misc symbol vectors and add each
>       symbol you find to the list.  Eventually we want to ignore
> @@ -5392,17 +5389,17 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>        ALL_MSYMBOLS (objfile, msymbol)
>  	{
>  	  QUIT;
> -	  MCOMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text,
> -				       word);
> +	  MCOMPLETION_LIST_ADD_SYMBOL (tracker, msymbol, sym_text,
> +				       sym_text_len, text, word);
>  
> -	  completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text,
> -				       word);
> +	  completion_list_objc_symbol (tracker, msymbol, sym_text,
> +				       sym_text_len, text, word);
>  	}
>      }
>  
>    /* Add completions for all currently loaded symbol tables.  */
>    ALL_COMPUNITS (objfile, cust)
> -    add_symtab_completions (cust, sym_text, sym_text_len, text, word,
> +    add_symtab_completions (cust, tracker, sym_text, sym_text_len, text, word,
>  			    code);
>  
>    /* Look through the partial symtabs for all symbols which begin
> @@ -5430,15 +5427,15 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>  	  {
>  	    if (code == TYPE_CODE_UNDEF)
>  	      {
> -		COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
> -					    word);
> -		completion_list_add_fields (sym, sym_text, sym_text_len, text,
> -					    word);
> +		COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
> +					    sym_text_len, text, word);
> +		completion_list_add_fields (tracker, sym, sym_text,
> +					    sym_text_len, text, word);
>  	      }
>  	    else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
>  		     && TYPE_CODE (SYMBOL_TYPE (sym)) == code)
> -	      COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
> -					  word);
> +	      COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
> +					  sym_text_len, text, word);
>  	  }
>  
>  	/* Stop when we encounter an enclosing function.  Do not stop for
> @@ -5455,11 +5452,13 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>      {
>        if (surrounding_static_block != NULL)
>  	ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
> -	  completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
> +	  completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
> +				      text, word);
>  
>        if (surrounding_global_block != NULL)
>  	ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
> -	  completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
> +	  completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
> +				      text, word);
>      }
>  
>    /* Skip macros if we are completing a struct tag -- arguable but
> @@ -5487,12 +5486,11 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
>        /* User-defined macros are always visible.  */
>        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,
> +default_make_symbol_completion_list_break_on (completion_tracker_t tracker,
> +					      const char *text,
>  					      const char *word,
>  					      const char *break_on,
>  					      enum type_code code)
> @@ -5505,7 +5503,7 @@ default_make_symbol_completion_list_break_on (const char *text,
>  
>    TRY_CATCH (except, RETURN_MASK_ERROR)
>      {
> -      default_make_symbol_completion_list_break_on_1 (text, word,
> +      default_make_symbol_completion_list_break_on_1 (tracker, text, word,
>  						      break_on, code);
>      }
>    if (except.reason < 0)
> @@ -5519,10 +5517,12 @@ default_make_symbol_completion_list_break_on (const char *text,
>  }
>  
>  VEC (char_ptr) *
> -default_make_symbol_completion_list (const char *text, const char *word,
> +default_make_symbol_completion_list (completion_tracker_t tracker,
> +				     const char *text, const char *word,
>  				     enum type_code code)
>  {
> -  return default_make_symbol_completion_list_break_on (text, word, "", code);
> +  return default_make_symbol_completion_list_break_on (tracker, text, word,
> +						       "", code);
>  }
>  
>  /* Return a vector of all symbols (regardless of class) which begin by
> @@ -5530,9 +5530,10 @@ default_make_symbol_completion_list (const char *text, const char *word,
>     is NULL.  */
>  
>  VEC (char_ptr) *
> -make_symbol_completion_list (const char *text, const char *word)
> +make_symbol_completion_list (completion_tracker_t tracker, const char *text,
> +			     const char *word)
>  {
> -  return current_language->la_make_symbol_completion_list (text, word,
> +  return current_language->la_make_symbol_completion_list (tracker, text, word,
>  							   TYPE_CODE_UNDEF);
>  }
>  
> @@ -5540,13 +5541,14 @@ make_symbol_completion_list (const char *text, const char *word)
>     symbols whose type code is CODE.  */
>  
>  VEC (char_ptr) *
> -make_symbol_completion_type (const char *text, const char *word,
> -			     enum type_code code)
> +make_symbol_completion_type (completion_tracker_t tracker, const char *text,
> +			     const char *word, enum type_code code)
>  {
>    gdb_assert (code == TYPE_CODE_UNION
>  	      || code == TYPE_CODE_STRUCT
>  	      || code == TYPE_CODE_ENUM);
> -  return current_language->la_make_symbol_completion_list (text, word, code);
> +  return current_language->la_make_symbol_completion_list (tracker, text,
> +							   word, code);
>  }
>  
>  /* Like make_symbol_completion_list, but suitable for use as a
> @@ -5554,16 +5556,18 @@ make_symbol_completion_type (const char *text, const char *word,
>  
>  VEC (char_ptr) *
>  make_symbol_completion_list_fn (struct cmd_list_element *ignore,
> +				completion_tracker_t tracker,
>  				const char *text, const char *word)
>  {
> -  return make_symbol_completion_list (text, word);
> +  return make_symbol_completion_list (tracker, text, word);
>  }
>  
>  /* Like make_symbol_completion_list, but returns a list of symbols
>     defined in a source file FILE.  */
>  
>  VEC (char_ptr) *
> -make_file_symbol_completion_list (const char *text, const char *word,
> +make_file_symbol_completion_list (completion_tracker_t tracker,
> +				  const char *text, const char *word,
>  				  const char *srcfile)
>  {
>    struct symbol *sym;
> @@ -5645,13 +5649,15 @@ make_file_symbol_completion_list (const char *text, const char *word,
>    b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), GLOBAL_BLOCK);
>    ALL_BLOCK_SYMBOLS (b, iter, sym)
>      {
> -      COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
> +      COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
> +				  word);
>      }
>  
>    b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), STATIC_BLOCK);
>    ALL_BLOCK_SYMBOLS (b, iter, sym)
>      {
> -      COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
> +      COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
> +				  word);
>      }
>  
>    return (return_val);
> @@ -5662,11 +5668,13 @@ make_file_symbol_completion_list (const char *text, const char *word,
>     list as necessary.  */
>  
>  static void
> -add_filename_to_list (const char *fname, const char *text, const char *word,
> +add_filename_to_list (completion_tracker_t tracker,
> +		      const char *fname, const char *text, const char *word,
>  		      VEC (char_ptr) **list)
>  {
>    char *new;
>    size_t fnlen = strlen (fname);
> +  enum maybe_add_completion_enum add_status;
>  
>    if (word == text)
>      {
> @@ -5688,7 +5696,22 @@ add_filename_to_list (const char *fname, const char *text, const char *word,
>        new[text - word] = '\0';
>        strcat (new, fname);
>      }
> -  VEC_safe_push (char_ptr, *list, new);
> +
> +  add_status = maybe_add_completion (tracker, new);
> +  switch (add_status)
> +    {
> +    case MAYBE_ADD_COMPLETION_OK:
> +      VEC_safe_push (char_ptr, *list, new);
> +      break;
> +    case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> +      VEC_safe_push (char_ptr, *list, new);
> +      /* fall through  */
> +    case MAYBE_ADD_COMPLETION_MAX_REACHED:

====

memory leak of new in MAYBE_ADD_COMPLETION_MAX_REACHED case.

> +      throw_max_completions_reached_error ();
> +      break;
> +    case MAYBE_ADD_COMPLETION_DUPLICATE:
> +      xfree (new);
> +    }
>  }
>  
>  static int
> @@ -5717,6 +5740,7 @@ struct add_partial_filename_data
>    const char *word;
>    int text_len;
>    VEC (char_ptr) **list;
> +  completion_tracker_t tracker;
>  };
>  
>  /* A callback for map_partial_symbol_filenames.  */
> @@ -5734,7 +5758,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
>      {
>        /* This file matches for a completion; add it to the
>  	 current list of matches.  */
> -      add_filename_to_list (filename, data->text, data->word, data->list);
> +      add_filename_to_list (data->tracker, filename, data->text, data->word,
> +			    data->list);
>      }
>    else
>      {
> @@ -5743,7 +5768,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
>        if (base_name != filename
>  	  && !filename_seen (data->filename_seen_cache, base_name, 1)
>  	  && filename_ncmp (base_name, data->text, data->text_len) == 0)
> -	add_filename_to_list (base_name, data->text, data->word, data->list);
> +	add_filename_to_list (data->tracker, base_name, data->text,
> +			      data->word, data->list);
>      }
>  }
>  
> @@ -5753,7 +5779,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
>     NULL.  */
>  
>  VEC (char_ptr) *
> -make_source_files_completion_list (const char *text, const char *word)
> +make_source_files_completion_list (completion_tracker_t tracker,
> +				   const char *text, const char *word)
>  {
>    struct compunit_symtab *cu;
>    struct symtab *s;
> @@ -5783,7 +5810,7 @@ make_source_files_completion_list (const char *text, const char *word)
>  	{
>  	  /* This file matches for a completion; add it to the current
>  	     list of matches.  */
> -	  add_filename_to_list (s->filename, text, word, &list);
> +	  add_filename_to_list (tracker, s->filename, text, word, &list);
>  	}
>        else
>  	{
> @@ -5795,7 +5822,7 @@ make_source_files_completion_list (const char *text, const char *word)
>  	  if (base_name != s->filename
>  	      && !filename_seen (filename_seen_cache, base_name, 1)
>  	      && filename_ncmp (base_name, text, text_len) == 0)
> -	    add_filename_to_list (base_name, text, word, &list);
> +	    add_filename_to_list (tracker, base_name, text, word, &list);
>  	}
>      }
>  
> @@ -5804,6 +5831,7 @@ make_source_files_completion_list (const char *text, const char *word)
>    datum.word = word;
>    datum.text_len = text_len;
>    datum.list = &list;
> +  datum.tracker = tracker;
>    map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
>  			0 /*need_fullname*/);
>  
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 0eb3a5b..572738a 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -23,6 +23,7 @@
>  #include "vec.h"
>  #include "gdb_vecs.h"
>  #include "gdbtypes.h"
> +#include "completer.h"
>  
>  /* Opaque declarations.  */
>  struct ui_file;
> @@ -1444,24 +1445,22 @@ extern void forget_cached_source_info (void);
>  extern void select_source_symtab (struct symtab *);
>  
>  extern VEC (char_ptr) *default_make_symbol_completion_list_break_on
> -  (const char *text, const char *word, const char *break_on,
> -   enum type_code code);
> -extern VEC (char_ptr) *default_make_symbol_completion_list (const char *,
> -							    const char *,
> -							    enum type_code);
> -extern VEC (char_ptr) *make_symbol_completion_list (const char *, const char *);
> -extern VEC (char_ptr) *make_symbol_completion_type (const char *, const char *,
> -						    enum type_code);
> -extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *,
> -						       const char *,
> -						       const char *);
> -
> -extern VEC (char_ptr) *make_file_symbol_completion_list (const char *,
> -							 const char *,
> -							 const char *);
> -
> -extern VEC (char_ptr) *make_source_files_completion_list (const char *,
> -							  const char *);
> +  (completion_tracker_t tracker, const char *text, const char *word,
> +   const char *break_on, enum type_code code);
> +extern VEC (char_ptr) *default_make_symbol_completion_list
> +  (completion_tracker_t tracker, const char *, const char *, enum type_code);
> +extern VEC (char_ptr) *make_symbol_completion_list
> +  (completion_tracker_t tracker, const char *, const char *);
> +extern VEC (char_ptr) *make_symbol_completion_type
> +  (completion_tracker_t, const char *, const char *, enum type_code);
> +extern VEC (char_ptr) *make_symbol_completion_list_fn
> +  (struct cmd_list_element *, completion_tracker_t, const char *, const char *);
> +
> +extern VEC (char_ptr) *make_file_symbol_completion_list
> +  (completion_tracker_t, const char *, const char *, const char *);
> +
> +extern VEC (char_ptr) *make_source_files_completion_list
> +  (completion_tracker_t, const char *, const char *);
>  
>  /* symtab.c */
>  
> diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp
> index f77bfe2..5afd851 100644
> --- a/gdb/testsuite/gdb.base/completion.exp
> +++ b/gdb/testsuite/gdb.base/completion.exp
> @@ -777,6 +777,84 @@ gdb_test_multiple "" "$test" {
>  }
>  
>  #
> +# Tests for the location completer
> +#
> +
> +# Turn off pending breakpoint support so that we don't get queried
> +# all the time.
> +gdb_test_no_output "set breakpoint pending off"
> +
> +set subsrc [string range $srcfile 0 [expr {[string length $srcfile] - 3}]]
> +set test "tab complete break $subsrc"
> +send_gdb "break $subsrc\t\t"
> +gdb_test_multiple "" $test {
> +    -re "break\.c.*break1\.c.*$gdb_prompt " {
> +	send_gdb "1\t\n"
> +	gdb_test_multiple "" $test {
> +	    -re ".*Function \"$srcfile2\" not defined\..*$gdb_prompt " {
> +		pass $test
> +	    }
> +	    -re "$gdb_prompt p$" {
> +		fail $test
> +	    }
> +	}
> +    }
> +
> +    -re "$gdb_prompt p$" {
> +	fail $test
> +    }
> +}
> +
> +gdb_test "complete break $subsrc" "break\.c.*break1\.c"
> +
> +# gdb/17960
> +set test "tab complete break $srcfile:ma"
> +send_gdb "break $srcfile:ma\t"
> +gdb_test_multiple "" $test {
> +    -re "break $srcfile:main " {
> +	send_gdb "\n"
> +	gdb_test_multiple "" $test {
> +	    -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
> +		pass $test
> +		gdb_test_no_output "delete breakpoint \$bpnum" \
> +		    "delete breakpoint for $test"
> +	    }
> +	    -re "$gdb_prompt p$" {
> +		fail $test
> +	    }
> +	}
> +    }
> +    -re "$gdb_prompt p$" {
> +	fail $test
> +    }
> +}
> +
> +gdb_test "complete break $srcfile:ma" "break\.c:main"
> +
> +set test "tab complete break need"
> +send_gdb "break need\t"
> +gdb_test_multiple "" $test {
> +    -re "break need_malloc " {
> +	send_gdb "\n"
> +	gdb_test_multiple "" $test {
> +	    -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
> +		pass $test
> +		gdb_test_no_output "delete breakpoint \$bpnum" \
> +		    "delete breakpoint for $test"
> +	    }
> +	    -re "$gdb_prompt p$" {
> +		fail $test
> +	    }
> +	}
> +    }
> +    -re "$gdb_prompt p$" {
> +	fail $test
> +    }
> +}
> +
> +gdb_test "complete break need" "need_malloc"
> +
> +#
>  # Completion limiting.
>  #
>  
> diff --git a/gdb/top.c b/gdb/top.c
> index 8242e12..af5d923 100644
> --- a/gdb/top.c
> +++ b/gdb/top.c
> @@ -1673,7 +1673,7 @@ set_verbose (char *args, int from_tty, struct cmd_list_element *c)
>    const char *cmdname = "verbose";
>    struct cmd_list_element *showcmd;
>  
> -  showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
> +  showcmd = lookup_cmd_1 (NULL, &cmdname, showlist, NULL, 1);
>    gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
>  
>    if (info_verbose)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]