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 v4 7/9] Explicit locations: add UI features for CLI


Keith Seitz <keiths@redhat.com> writes:
> This patch exposes explicit locations to the CLI user.  This enables
> users to "explicitly" specify attributes of the breakpoint location
> to avoid any ambiguity that might otherwise exist with linespecs.
>
> The general syntax of explicit locations is:
> -source SOURCE_FILENAME -line {+-}LINE -function FUNCTION_NAME
> -label LABEL_NAME
>
> Option names may be abbreviated, e.g., "-s SOURCE_FILENAME -li 3" and users
> may use the completer with either options or values.
>
> gdb/ChangeLog:
>
> 	* completer.c: Include location.h.
> 	(enum match_type): New enum.
> 	(location_completer): Rename to ...
> 	(linespec_completer): ... this.
> 	(collect_explicit_location_matches, backup_text_ptr)
> 	(explicit_location_completer): New functions.
> 	(location_completer): "New" function; handle linespec
> 	and explicit location completions.
> 	(complete_line_internal): Remove all location completer-specific
> 	handling.
> 	* linespec.c (linespec_lexer_lex_keyword): Export.
> 	(is_ada_operator): Ditto.
> 	(find_toplevel_char): Ditto.
> 	(linespec_parse_line_offset): Ditto.
> 	Issue error if STRING is not numerical.
> 	(gdb_get_linespec_parser_quote_characters): New function.
> 	* linespec.h (linespec_parse_line_offset): Declare.
> 	(get_gdb_linespec_parser_quote_characters): Declare.
> 	(is_ada_operator): Declare.
> 	(find_toplevel_char): Declare.
> 	(linespec_lexer_lex_keyword): Declare.
> 	* location.c (explicit_to_event_location): New function.
> 	(explicit_location_lex_one): New function.
> 	(string_to_explicit_location): New function.
> 	(string_to_event_location): Handle explicit locations.
> 	* location.h (explicit_to_event_location): Declare.
> 	(string_to_explicit_location): Declare.
>
> gdb/testsuite/ChangeLog:
>
> 	* gdb.linespec/3explicit.c: New file.
> 	* gdb.linespec/cpexplicit.cc: New file.
> 	* gdb.linespec/cpexplicit.exp: New file.
> 	* gdb.linespec/explicit.c: New file.
> 	* gdb.linespec/explicit.exp: New file.
> 	* gdb.linespec/explicit2.c: New file.
> 	* gdb.linespec/ls-errs.exp: Add explicit location tests.

LGTM, with a couple of nits below.

>...
> diff --git a/gdb/completer.c b/gdb/completer.c
> index c8c0e4c..b9ae591 100644
> --- a/gdb/completer.c
> +++ b/gdb/completer.c
> @@ -26,6 +26,7 @@
>  #include "target.h"
>  #include "reggroups.h"
>  #include "user-regs.h"
> +#include "location.h"
>  
>  #include "cli/cli-decode.h"
>  
> @@ -42,6 +43,21 @@
>  
>  #include "completer.h"
>  
> +/* An enumeration of the various things a user might
> +   attempt to complete for a location.  */
> +
> +enum explicit_location_match_type
> +{
> +    /* The filename of a source file.  */
> +    MATCH_SOURCE,
> +
> +    /* The name of a function or method.  */
> +    MATCH_FUNCTION,
> +
> +    /* The name of a label.  */
> +    MATCH_LABEL
> +};
> +
>  /* Prototypes for local functions.  */
>  static
>  char *line_completion_function (const char *text, int matches, 
> @@ -174,7 +190,7 @@ filename_completer (struct cmd_list_element *ignore,
>    return return_val;
>  }
>  
> -/* Complete on locations, which might be of two possible forms:
> +/* Complete on linespecs, which might be of two possible forms:
>  
>         file:line
>     or
> @@ -183,9 +199,9 @@ filename_completer (struct cmd_list_element *ignore,
>     This is intended to be used in commands that set breakpoints
>     etc.  */
>  
> -VEC (char_ptr) *
> -location_completer (struct cmd_list_element *ignore, 
> -		    const char *text, const char *word)
> +static VEC (char_ptr) *
> +linespec_location_completer (struct cmd_list_element *ignore,
> +			     const char *text, const char *word)
>  {
>    int n_syms, n_files, ix;
>    VEC (char_ptr) *fn_list = NULL;
> @@ -332,6 +348,183 @@ location_completer (struct cmd_list_element *ignore,
>    return list;
>  }
>  
> +/* A helper function to collect explicit location matches for the given
> +   LOCATION, which is attempting to match on WORD.  */
> +
> +static VEC (char_ptr) *
> +collect_explicit_location_matches (struct event_location *location,
> +				   enum explicit_location_match_type what,
> +				   const char *word)
> +{
> +  VEC (char_ptr) *matches = NULL;
> +  const struct explicit_location *explicit = get_explicit_location (location);
> +
> +  switch (what)
> +    {
> +    case MATCH_SOURCE:
> +      {
> +	const char *text = (explicit->source_filename == NULL
> +			    ? "" : explicit->source_filename);
> +
> +	matches = make_source_files_completion_list (text, word);
> +      }
> +      break;
> +
> +    case MATCH_FUNCTION:
> +      {
> +	const char *text = (explicit->function_name == NULL
> +			    ? "" : explicit->function_name);
> +
> +	if (explicit->source_filename != NULL)
> +	  {
> +	    matches
> +	      = make_file_symbol_completion_list (text, word,
> +						  explicit->source_filename);
> +	  }
> +	else
> +	  matches = make_symbol_completion_list (text, word);
> +      }
> +      break;
> +
> +    case MATCH_LABEL:
> +      /* Not supported.  */
> +      break;
> +
> +    default:
> +      gdb_assert_not_reached ("unhandled explicit_location_match_type");
> +    }
> +
> +  return matches;
> +}
> +
> +/* A convenience macro to (safely) back up P to the previous word.  */
> +
> +static const char *
> +backup_text_ptr (const char *p, const char *text)
> +{
> +  while (p > text && isspace (*p))
> +    --p;
> +  for (; p > text && !isspace (p[-1]); --p)
> +    ;
> +
> +  return p;
> +}
> +
> +/* A completer function for explicit locations.  This function
> +   completes both options ("-source", "-line", etc) and values.  */
> +
> +static VEC (char_ptr) *
> +explicit_location_completer (struct cmd_list_element *ignore,
> +			     struct event_location *location,
> +			     const char *text, const char *word)
> +{
> +  const char *p;
> +  VEC (char_ptr) *matches = NULL;
> +
> +  /* Find the beginning of the word.  This is necessary because
> +     we need to know if we are completing an option name or value.  We
> +     don't get the leading '-' from the completer.  */
> +  p = backup_text_ptr (word, text);
> +
> +  if (*p == '-')
> +    {
> +      size_t len = strlen (word);
> +
> +      /* Completing on option name.  */
> +
> +      /* Skip over the '-'.  */
> +      ++p;
> +
> +      if (strncmp (p, "source", len) == 0)
> +	VEC_safe_push (char_ptr, matches, xstrdup ("source"));
> +      if (strncmp (p, "function", len) == 0)
> +	VEC_safe_push (char_ptr, matches, xstrdup ("function"));
> +      if (strncmp (p, "line", len) == 0)
> +	VEC_safe_push (char_ptr, matches, xstrdup ("line"));
> +      if (strncmp (p, "label", len) == 0)
> +	VEC_safe_push (char_ptr, matches, xstrdup ("label"));
> +    }
> +  else
> +    {
> +      /* Completing on value (or unknown).  Get the previous word to see what
> +	 the user is completing on.  */
> +      size_t len, offset;
> +      const char *new_word, *end;
> +      enum explicit_location_match_type what;
> +      struct explicit_location *explicit = get_explicit_location (location);
> +
> +      /* Backup P to the previous word, which should be the option
> +	 the user is attempting to complete.  */
> +      offset = word - p;
> +      end = --p;
> +      p = backup_text_ptr (p, text);
> +      len = end - p;
> +
> +      if (strncmp (p, "-source", len) == 0)
> +	{
> +	  what = MATCH_SOURCE;
> +	  new_word = explicit->source_filename + offset;
> +	}
> +      else if (strncmp (p, "-function", len) == 0)
> +	{
> +	  what = MATCH_FUNCTION;
> +	  new_word = explicit->function_name + offset;
> +	}
> +      else if (strncmp (p, "-label", len) == 0)
> +	{
> +	  what = MATCH_LABEL;
> +	  new_word = explicit->label_name + offset;
> +	}
> +      else
> +	{
> +	  /* The user isn't completing on any valid option name,
> +	     e.g., "break -source foo.c [tab]".  */
> +	  return NULL;
> +	}
> +
> +      /* If the user hasn't entered a search expression, e.g.,
> +	 "break -function <TAB><TAB>", new_word will be NULL, but
> +	 search routines require non-NULL search words.  */
> +      if (new_word == NULL)
> +	new_word = "";
> +
> +      /* Now gather matches  */
> +      matches = collect_explicit_location_matches (location, what, new_word);
> +    }
> +
> +  return matches;
> +}
> +
> +/* A completer for locations.  */
> +
> +VEC (char_ptr) *
> +location_completer (struct cmd_list_element *ignore,
> +		    const char *text, const char *word)
> +{
> +  VEC (char_ptr) *matches = NULL;
> +  const char *copy = text;
> +  struct event_location *location;
> +
> +  location = string_to_explicit_location (&copy, current_language, 1);
> +  if (location != NULL)
> +    {
> +      struct cleanup *cleanup;
> +
> +      cleanup = make_cleanup_delete_event_location (location);
> +      matches = explicit_location_completer (ignore, location, text, word);
> +      do_cleanups (cleanup);
> +    }
> +  else
> +    {
> +      /* This is an address or linespec location.
> +	 Right now both of these are handled by the (old) linespec
> +	 completer.  */
> +      matches = linespec_location_completer (ignore, text, word);
> +    }
> +
> +  return matches;
> +}
> +
>  /* Helper for expression_completer which recursively adds field and
>     method names from TYPE, a struct or union type, to the array
>     OUTPUT.  */
> @@ -687,16 +880,6 @@ complete_line_internal (const char *text,
>  		      rl_completer_word_break_characters =
>  			gdb_completer_file_name_break_characters;
>  		    }
> -		  else if (c->completer == location_completer)
> -		    {
> -		      /* Commands which complete on locations want to
> -			 see the entire argument.  */
> -		      for (p = word;
> -			   p > tmp_command
> -			     && p[-1] != ' ' && p[-1] != '\t';
> -			   p--)
> -			;
> -		    }
>  		  if (reason == handle_brkchars
>  		      && c->completer_handle_brkchars != NULL)
>  		    (*c->completer_handle_brkchars) (c, p, word);
> @@ -765,14 +948,6 @@ complete_line_internal (const char *text,
>  		  rl_completer_word_break_characters =
>  		    gdb_completer_file_name_break_characters;
>  		}
> -	      else if (c->completer == location_completer)
> -		{
> -		  for (p = word;
> -		       p > tmp_command
> -			 && p[-1] != ' ' && p[-1] != '\t';
> -		       p--)
> -		    ;
> -		}
>  	      if (reason == handle_brkchars
>  		  && c->completer_handle_brkchars != NULL)
>  		(*c->completer_handle_brkchars) (c, p, word);
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index a7e6248..3fe2dbd 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -323,8 +323,6 @@ static int compare_symbols (const void *a, const void *b);
>  
>  static int compare_msymbols (const void *a, const void *b);
>  
> -static const char *find_toplevel_char (const char *s, char c);
> -
>  /* Permitted quote characters for the parser.  This is different from the
>     completer's quote characters to allow backward compatibility with the
>     previous parser.  */
> @@ -419,10 +417,9 @@ linespec_lexer_lex_keyword (const char *p)
>    return NULL;
>  }
>  
> -/* Does STRING represent an Ada operator?  If so, return the length
> -   of the decoded operator name.  If not, return 0.  */
> +/*  See description in linespec.h.  */
>  
> -static int
> +int
>  is_ada_operator (const char *string)
>  {
>    const struct ada_opname_map *mapping;
> @@ -1140,7 +1137,7 @@ find_methods (struct type *t, const char *name,
>     strings.  Also, ignore the char within a template name, like a ','
>     within foo<int, int>.  */
>  
> -static const char *
> +const char *
>  find_toplevel_char (const char *s, char c)
>  {
>    int quoted = 0;		/* zero if we're not in quotes;
> @@ -1551,11 +1548,12 @@ source_file_not_found_error (const char *name)
>    throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
>  }
>  
> -/* Parse and return a line offset in STRING.  */
> +/* See description in linespec.h.  */
>  
> -static struct line_offset
> +struct line_offset
>  linespec_parse_line_offset (const char *string)
>  {
> +  const char *start = string;
>    struct line_offset line_offset = {0, LINE_OFFSET_NONE};
>  
>    if (*string == '+')
> @@ -1569,6 +1567,9 @@ linespec_parse_line_offset (const char *string)
>        ++string;
>      }
>  
> +  if (*string != '\0' && !isdigit (*string))
> +    error (_("malformed line offset: \"%s\""), start);
> +
>    /* Right now, we only allow base 10 for offsets.  */
>    line_offset.offset = atoi (string);
>    return line_offset;
> @@ -3890,3 +3891,11 @@ make_cleanup_destroy_linespec_result (struct linespec_result *ls)
>  {
>    return make_cleanup (cleanup_linespec_result, ls);
>  }
> +
> +/* Return the quote characters permitted by the linespec parser.  */
> +
> +const char *
> +get_gdb_linespec_parser_quote_characters (void)
> +{
> +  return linespec_quote_characters;
> +}
> diff --git a/gdb/linespec.h b/gdb/linespec.h
> index 391ed26..2a76283 100644
> --- a/gdb/linespec.h
> +++ b/gdb/linespec.h
> @@ -157,6 +157,26 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
>  
>  extern const char *linespec_lexer_lex_keyword (const char *p);
>  
> +/* Parse a line offset from STRING.  */
> +
> +extern struct line_offset linespec_parse_line_offset (const char *string);
> +
> +/* Return the quote characters permitted by the linespec parser.  */
> +
> +extern const char *get_gdb_linespec_parser_quote_characters (void);
> +
> +/* Does STRING represent an Ada operator?  If so, return the length
> +   of the decoded operator name.  If not, return 0.  */
> +
> +extern int is_ada_operator (const char *string);
> +
> +/* Find an instance of the character C in the string S that is outside
> +   of all parenthesis pairs, single-quoted strings, and double-quoted
> +   strings.  Also, ignore the char within a template name, like a ','
> +   within foo<int, int>.  */
> +
> +extern const char *find_toplevel_char (const char *s, char c);
> +
>  /* Find the end of the (first) linespec pointed to by *STRINGP.
>     STRINGP will be advanced to this point.  */
>  
> diff --git a/gdb/location.c b/gdb/location.c
> index 7882b2d..779bcfa 100644
> --- a/gdb/location.c
> +++ b/gdb/location.c
> @@ -442,6 +442,203 @@ event_location_to_string (struct event_location *location)
>    return EL_STRING (location);
>  }
>  
> +/* A lexer for explicit locations.  This function will advance INP
> +   past any strings that it lexes.  Returns a malloc'd copy of the
> +   lexed string or NULL if no lexing was done.  */
> +
> +static char *
> +explicit_location_lex_one (const char **inp,
> +			   const struct language_defn *language)
> +{
> +  const char *start = *inp;
> +
> +  if (*start == '\0')
> +    return NULL;
> +
> +  /* If quoted, skip to the ending quote.  */
> +  if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
> +    {
> +      char quote_char = *start;
> +
> +      /* If the input is not an Ada operator, skip to the matching
> +	 closing quote and return the string.  */
> +      if (!(language->la_language == language_ada
> +	    && quote_char == '\"' && is_ada_operator (start)))
> +	{
> +	  const char *end = find_toplevel_char (start + 1, quote_char);
> +
> +	  if (end == NULL)
> +	    error (_("Unmatched quote, %s."), start);
> +	  *inp = end + 1;
> +	  return savestring (start + 1, *inp - start - 2);
> +	}
> +    }
> +
> +  /* If the input starts with '-' or '+', the string ends with the next
> +     whitespace.  */
> +  if (*start == '-' || *start == '+')
> +    *inp = skip_to_space_const (*inp);

I suspect this is just following what the existing code does,
but why not also watch for commas when there's a leading +,-?
If this is just following code and there's an issue here
I'd leave it for another day to change.

> +  else
> +    {
> +      /* Handle numbers first, stopping at the next whitespace or ','.  */
> +      while (isdigit (*inp[0]))
> +	++(*inp);
> +      if (*inp[0] == '\0' || isspace (*inp[0]) || *inp[0] == ',')
> +	return savestring (start, *inp - start);
> +
> +      /* Otherwise stop at the next occurrence of "SPACE -", '\0',
> +	 keyword, or ','.  */
> +      *inp = start;
> +      while ((*inp)[0]
> +	     && (*inp)[0] != ','
> +	     && !(isspace ((*inp)[0])
> +		  && ((*inp)[1] == '-'
> +		      || linespec_lexer_lex_keyword (&(*inp)[1]))))
> +	{
> +	  /* Special case: C++ operator,.  */
> +	  if (language->la_language == language_cplus
> +	      && strncmp (*inp, "operator", 8)
> +	      && (*inp)[9] == ',')
> +	    (*inp) += 9;
> +	  ++(*inp);
> +	}
> +    }
> +
> +  if (*inp - start > 0)
> +    return savestring (start, *inp - start);
> +
> +  return NULL;
> +}
> +
> +/* See description in location.h.  */
> +
> +struct event_location *
> +string_to_explicit_location (const char **argp,
> +			     const struct language_defn *language,
> +			     int dont_throw)
> +{
> +  struct cleanup *cleanup;
> +  struct event_location *location;
> +
> +  /* It is assumed that input beginning with '-' and a non-digit
> +     character is an explicit location.  */
> +  if (argp == NULL
> +      || *argp == '\0'
> +      || *argp[0] != '-'
> +      || !isalpha ((*argp)[1]))
> +    return NULL;
> +
> +  location = new_explicit_location (NULL);
> +  cleanup = make_cleanup_delete_event_location (location);
> +
> +  /* Process option/argument pairs.  dprintf_command
> +     requires that processing stop on ','.  */
> +  while ((*argp)[0] != '\0' && (*argp)[0] != ',')
> +    {
> +      int len;
> +      char *opt, *oarg;
> +      const char *start;
> +      struct cleanup *inner;
> +
> +      /* If *ARGP starts with a keyword, stop processing
> +	 options.  */
> +      if (linespec_lexer_lex_keyword (*argp) != NULL)
> +	break;
> +
> +      /* Mark the start of the string in case we need to rewind.  */
> +      start = *argp;
> +
> +      /* Get the option string.  */
> +      opt = explicit_location_lex_one (argp, language);
> +      inner = make_cleanup (xfree, opt);
> +
> +      *argp = skip_spaces_const (*argp);
> +
> +      /* Get the argument string.  */
> +      oarg = explicit_location_lex_one (argp, language);
> +
> +      *argp = skip_spaces_const (*argp);
> +
> +      /* Use the length of the option to allow abbreviations.  */
> +      len = strlen (opt);
> +
> +      /* All options have a required argument.  Checking for this required
> +	 argument is deferred until later.  */
> +      if (strncmp (opt, "-source", len) == 0)
> +	EL_EXPLICIT (location)->source_filename = oarg;
> +      else if (strncmp (opt, "-function", len) == 0)
> +	EL_EXPLICIT (location)->function_name = oarg;
> +      else if (strncmp (opt, "-line", len) == 0)
> +	{
> +	  if (oarg != NULL)
> +	    {
> +	      TRY
> +		{
> +		  EL_EXPLICIT (location)->line_offset
> +		    = linespec_parse_line_offset (oarg);
> +		}
> +	      CATCH (e, RETURN_MASK_ERROR)
> +		{
> +		  xfree (oarg);

Could other exception types leak oarg here?

> +		  throw_exception (e);
> +		}
> +	      END_CATCH
> +	      xfree (oarg);
> +	      do_cleanups (inner);
> +	      continue;
> +	    }
> +	}
> +      else if (strncmp (opt, "-label", len) == 0)
> +	EL_EXPLICIT (location)->label_name = oarg;
> +      /* Only emit an "invalid argument" error for options
> +	 that look like option strings.  */
> +      else if (opt[0] == '-' && !isdigit (opt[1]))
> +	{
> +	  xfree (oarg);
> +	  if (!dont_throw)
> +	    error (_("invalid explicit location argument, \"%s\""), opt);
> +	}
> +      else
> +	{
> +	  /* End of the explicit location specification.
> +	     Stop parsing and return whatever explicit location was
> +	     parsed.  */
> +	  *argp = start;
> +	  xfree (oarg);
> +	  do_cleanups (inner);
> +	  discard_cleanups (cleanup);
> +	  return location;
> +	}
> +
> +      /* It's a little lame to error after the fact, but in this
> +	 case, it provides a much better user experience to issue
> +	 the "invalid argument" error before any missing
> +	 argument error.  */
> +      if (oarg == NULL && !dont_throw)
> +	error (_("missing argument for \"%s\""), opt);
> +
> +      /* The option/argument pari was successfully processed;
> +	 oarg belongs to the explicit location, and opt should
> +	 be freed.  */
> +      do_cleanups (inner);
> +    }
> +
> +  /* One special error check:  If a source filename was given
> +     without offset, function, or label, issue an error.  */
> +  if (EL_EXPLICIT (location)->source_filename != NULL
> +      && EL_EXPLICIT (location)->function_name == NULL
> +      && EL_EXPLICIT (location)->label_name == NULL
> +      && (EL_EXPLICIT (location)->line_offset.sign == LINE_OFFSET_UNKNOWN)
> +      && !dont_throw)
> +    {
> +      error (_("Source filename requires function, label, or "
> +	       "line offset."));
> +    }
> +
> +  discard_cleanups (cleanup);
> +  return location;
> +}
> +
>  /* See description in location.h.  */
>  
>  struct event_location *
> @@ -474,8 +671,22 @@ string_to_event_location (char **stringp,
>  	}
>        else
>  	{
> -	  /* Everything else is a linespec.  */
> -	  location = new_linespec_location (stringp);
> +	  const char *arg, *orig;
> +
> +	  /* Next, try an explicit location.  */
> +	  orig = arg = *stringp;
> +	  location = string_to_explicit_location (&arg, language, 0);
> +	  if (location != NULL)
> +	    {
> +	      /* It was a valid explicit location.  Advance STRINGP to
> +		 the end of input.  */
> +	      *stringp += arg - orig;
> +	    }
> +	  else
> +	    {
> +	      /* Everything else is a linespec.  */
> +	      location = new_linespec_location (stringp);
> +	    }
>  	}
>      }
>  
> diff --git a/gdb/location.h b/gdb/location.h
> index fba1c17..9dc557d 100644
> --- a/gdb/location.h
> +++ b/gdb/location.h
> @@ -210,6 +210,21 @@ extern struct event_location *
>    string_to_event_location (char **argp,
>  			    const struct language_defn *langauge);
>  
> +/* Attempt to convert the input string in *ARGP into an explicit location.
> +   ARGP is advanced past any processed input.  Returns an event_location
> +   (malloc'd) if an explicit location was successfully found in *ARGP,
> +   NULL otherwise.
> +
> +   IF !DONT_THROW, this function may call error() if *ARGP looks like
> +   properly formed input, e.g., if it is called with missing argument
> +   parameters or invalid options.  If DONT_THROW is non-zero, this function
> +   will not throw any exceptions.  */
> +
> +extern struct event_location *
> +  string_to_explicit_location (const char **argp,
> +			       const struct language_defn *langauge,
> +			       int dont_throw);
> +
>  /* A convenience function for testing for unset locations.  */
>  
>  extern int event_location_empty_p (const struct event_location *location);
> diff --git a/gdb/testsuite/gdb.linespec/3explicit.c b/gdb/testsuite/gdb.linespec/3explicit.c
> new file mode 100644
> index 0000000..12bf277
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/3explicit.c
> @@ -0,0 +1,28 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +static int
> +myfunction4 (int arg)
> +{
> +  return arg + 2;
> +}
> +
> +int
> +myfunction3 (int arg)
> +{
> +  return myfunction4 (arg);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.cc b/gdb/testsuite/gdb.linespec/cpexplicit.cc
> new file mode 100644
> index 0000000..42d50c7
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/cpexplicit.cc
> @@ -0,0 +1,63 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2012-2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +class myclass
> +{
> +public:
> +  static int myfunction (int arg)  /* entry location */
> +  {
> +    int i, j, r;
> +
> +    j = 0; /* myfunction location */
> +    r = arg;
> +
> +  top:
> +    ++j;  /* top location */
> +
> +    if (j == 10)
> +      goto done;
> +
> +    for (i = 0; i < 10; ++i)
> +      {
> +	r += i;
> +	if (j % 2)
> +	  goto top;
> +      }
> +
> +  done:
> +    return r;
> +  }
> +
> +  int operator, (const myclass& c) { return 0; } /* operator location */
> +};
> +
> +int
> +main (void)
> +{
> +  int i, j;
> +
> +  /* Call the test function repeatedly, enough times for all our tests
> +     without running forever if something goes wrong.  */
> +  myclass c, d;
> +  for (i = 0, j = 0; i < 1000; ++i)
> +    {
> +      j += myclass::myfunction (0);
> +      j += (c,d);
> +    }
> +
> +  return j;
> +}
> diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.exp b/gdb/testsuite/gdb.linespec/cpexplicit.exp
> new file mode 100644
> index 0000000..90c8ce8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
> @@ -0,0 +1,112 @@
> +# Copyright 2012-2015 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tests for explicit linespecs
> +
> +if {[skip_cplus_tests]} {
> +    unsupported "skipping C++ tests"
> +    return
> +}
> +
> +standard_testfile .cc
> +set exefile $testfile
> +
> +if {[prepare_for_testing $testfile $exefile $srcfile \
> +	 {c++ debug nowarnings}]} {
> +    return -1
> +}
> +
> +# Wrap this whole test in a namespace to avoid contaminating other tests.
> +namespace eval $testfile {
> +    # Test the given (explicit) LINESPEC which should cause gdb to break
> +    # at LOCATION.
> +    proc test_breakpoint {linespec location} {
> +
> +	# Delete all breakpoints, set a new breakpoint at LINESPEC,
> +	# and attempt to run to it.
> +	delete_breakpoints
> +	gdb_breakpoint $linespec
> +	gdb_continue_to_breakpoint $linespec $location
> +    }
> +
> +    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
> +    # to stop at LOCATION.
> +    proc add {thearray linespec location} {
> +	upvar $thearray ar
> +
> +	lappend ar(linespecs) $linespec
> +	lappend ar(locations) $location
> +    }
> +
> +    # Some locations used in this test
> +    variable lineno
> +    variable location
> +    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
> +    set lineno(entry) [gdb_get_line_number "entry location" $srcfile]
> +    set lineno(top) [gdb_get_line_number "top location" $srcfile]
> +    set lineno(operator) [gdb_get_line_number "operator location" $srcfile]
> +    foreach v [array names lineno] {
> +	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
> +    }
> +
> +    # A list of explicit linespecs and the corresponding location
> +    variable linespecs
> +    set linespecs(linespecs) {}
> +    set linespecs(location) {}
> +
> +    add linespecs "-source $srcfile -function myclass::myfunction" \
> +	$location(normal)
> +    add linespecs "-source $srcfile -function myclass::myfunction -label top" \
> +	$location(top)
> +
> +    # This isn't implemented yet; -line is silently ignored.
> +    add linespecs \
> +	"-source $srcfile -function myclass::myfunction -label top -line 3" \
> +	$location(top)
> +    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
> +    add linespecs "-function myclass::myfunction" $location(normal)
> +    add linespecs "-function myclass::myfunction -label top" $location(top)
> +
> +    # These are also not yet supported; -line is silently ignored.
> +    add linespecs "-function myclass::myfunction -line 3" $location(normal)
> +    add linespecs "-function myclass::myfunction -label top -line 3" \
> +	$location(top)
> +    add linespecs "-line 3" $location(normal)
> +    add linespecs "-function myclass::operator," $location(operator)
> +    add linespecs "-function 'myclass::operator,'" $location(operator)
> +    add linespecs "-function \"myclass::operator,\"" $location(operator)
> +
> +    # Fire up gdb.
> +    if {![runto_main]} {
> +	namespace delete $testfile
> +	return -1
> +    }
> +
> +    # Test explicit linespecs, with and without conditions.
> +    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
> +	# Test the linespec
> +	test_breakpoint $linespec $loc_pattern
> +    }
> +
> +    # Special (orphaned) dprintf cases.
> +    gdb_test "dprintf -function myclass::operator,,\"hello\"" \
> +	"Dprintf .*$srcfile, line $lineno(operator)\\."
> +    gdb_test "dprintf -function 'myclass::operator,',\"hello\"" \
> +	"Dprintf .*$srcfile, line $lineno(operator)\\."
> +    gdb_test "dprintf -function \"myclass::operator,\",\"hello\"" \
> +	"Dprintf .*$srcfile, line $lineno(operator)\\."
> +}
> +
> +namespace delete $testfile
> diff --git a/gdb/testsuite/gdb.linespec/explicit.c b/gdb/testsuite/gdb.linespec/explicit.c
> new file mode 100644
> index 0000000..4e1c635
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit.c
> @@ -0,0 +1,56 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2012-2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +extern int myfunction2 (int arg);
> +
> +static int
> +myfunction (int arg)
> +{
> +  int i, j, r;
> +
> +  j = 0; /* myfunction location */
> +  r = arg;
> +
> + top:
> +  ++j;  /* top location */
> +
> +  if (j == 10)
> +    goto done;
> +
> +  for (i = 0; i < 10; ++i)
> +    {
> +      r += i;
> +      if (j % 2)
> +	goto top;
> +    }
> +
> + done:
> +  return r;
> +}
> +
> +int
> +main (void)
> +{
> +  int i, j;
> +
> +  /* Call the test function repeatedly, enough times for all our tests
> +     without running forever if something goes wrong.  */
> +  for (i = 0, j = 0; i < 1000; ++i)
> +    j += myfunction (0);
> +
> +  return myfunction2 (j);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
> new file mode 100644
> index 0000000..ce65bfd
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit.exp
> @@ -0,0 +1,393 @@
> +# Copyright 2012-2015 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tests for explicit locations
> +
> +standard_testfile explicit.c explicit2.c 3explicit.c
> +set exefile $testfile
> +
> +if {[prepare_for_testing $testfile $exefile \
> +	 [list $srcfile $srcfile2 $srcfile3] {debug nowarnings}]} {
> +    return -1
> +}
> +
> +# Wrap the entire test in a namespace to avoid contaminating other tests.
> +namespace eval $testfile {
> +
> +    # Test the given (explicit) LINESPEC which should cause gdb to break
> +    # at LOCATION.
> +    proc test_breakpoint {linespec location} {
> +
> +	set testname "set breakpoint at \"$linespec\""
> +	# Delete all breakpoints, set a new breakpoint at LINESPEC,
> +	# and attempt to run to it.
> +	delete_breakpoints
> +	if {[gdb_breakpoint $linespec]} {
> +	    pass $testname
> +	    send_log "\nexpecting locpattern \"$location\"\n"
> +	    gdb_continue_to_breakpoint $linespec $location
> +	} else {
> +	    fail $testname
> +	}
> +    }
> +
> +    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
> +    # to stop at LOCATION.
> +    proc add {thearray linespec location} {
> +	upvar $thearray ar
> +
> +	lappend ar(linespecs) $linespec
> +	lappend ar(locations) $location
> +    }
> +
> +    # A list of all explicit linespec arguments.
> +    variable all_arguments
> +    set all_arguments {"source" "function" "label" "line"}
> +
> +    # Some locations used in this test
> +    variable lineno
> +    variable location
> +    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
> +    set lineno(top) [gdb_get_line_number "top location" $srcfile]
> +    foreach v [array names lineno] {
> +	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
> +    }
> +
> +    # A list of explicit locations and the corresponding location.
> +    variable linespecs
> +    set linespecs(linespecs) {}
> +    set linespecs(location) {}
> +
> +    add linespecs "-source $srcfile -function myfunction" $location(normal)
> +    add linespecs "-source $srcfile -function myfunction -label top" \
> +	$location(top)
> +
> +    # This isn't implemented yet; -line is silently ignored.
> +    add linespecs "-source $srcfile -function myfunction -label top -line 3" \
> +	$location(top)
> +    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
> +    add linespecs "-function myfunction" $location(normal)
> +    add linespecs "-function myfunction -label top" $location(top)
> +
> +    # These are also not yet supported; -line is silently ignored.
> +    add linespecs "-function myfunction -line 3" $location(normal)
> +    add linespecs "-function myfunction -label top -line 3" $location(top)
> +    add linespecs "-line 3" $location(normal)
> +
> +    # Test that static tracepoints on marker ID are not interpreted
> +    # as an erroneous explicit option.
> +    gdb_test "strace -m gdbfoobarbaz" "You can't do that.*"
> +
> +    # Fire up gdb.
> +    if {![runto_main]} {
> +	return -1
> +    }
> +
> +    # Turn off queries
> +    gdb_test_no_output "set confirm off"
> +
> +    # Simple error tests (many more are tested in ls-err.exp)
> +    foreach arg $all_arguments {
> +	# Test missing argument
> +	gdb_test "break -$arg" \
> +	    [string_to_regexp "missing argument for \"-$arg\""]
> +
> +	# Test abbreviations
> +	set short [string range $arg 0 3]
> +	gdb_test "break -$short" \
> +	    [string_to_regexp "missing argument for \"-$short\""]
> +    }
> +
> +    # Test invalid arguments
> +    foreach arg {"-foo" "-foo bar" "-function myfunction -foo" \
> +		     "-function -myfunction -foo bar"} {
> +	gdb_test "break $arg" \
> +	    [string_to_regexp "invalid explicit location argument, \"-foo\""]
> +    }
> +
> +    # Test explicit locations, with and without conditions.
> +    # For these tests, it is easiest to turn of pending breakpoint.
> +    gdb_test_no_output "set breakpoint pending off" \
> +	"turn off pending breakpoints"
> +
> +    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
> +
> +	# Test the linespec
> +	test_breakpoint $linespec $loc_pattern
> +
> +	# Test with a valid condition
> +	delete_breakpoints
> +	set tst "set breakpoint at \"$linespec\" with valid condition"
> +	if {[gdb_breakpoint "$linespec if arg == 0"]} {
> +	    pass $tst
> +
> +	    gdb_test "info break" ".*stop only if arg == 0.*" \
> +		"info break of conditional breakpoint at \"$linespec\""
> +	} else {
> +	    fail $tst
> +	}
> +
> +	# Test with invalid condition
> +	gdb_test "break $linespec if foofoofoo == 1" \
> +	    ".*No symbol \"foofoofoo\" in current context.*" \
> +	    "set breakpoint at \"$linespec\" with invalid condition"
> +
> +	# Test with thread
> +	delete_breakpoints
> +	gdb_test "break $linespec thread 123" "Unknown thread 123."
> +    }
> +
> +    # Test the explicit location completer
> +    foreach abbrev {"fun" "so" "lab" "li"}  full {"function" "source" "label" "line"} {
> +	set tst "complete 'break -$abbrev'"
> +	send_gdb "break -${abbrev}\t"
> +	gdb_test_multiple "" $tst {
> +	    "break -$full " {
> +		send_gdb "\n"
> +		gdb_test_multiple "" $tst {
> +		    -re "missing argument for \"-$full\".*$gdb_prompt " {
> +			pass $tst
> +		    }
> +		}
> +	    }
> +	}
> +	set tst "complete -$full with no value"
> +	send_gdb "break -$full \t"
> +	gdb_test_multiple "" $tst {
> +	    -re ".*break -$full " {
> +		send_gdb "\n"
> +		gdb_test_multiple "" $tst {
> +		    -re ".*Source filename requires function, label, or line offset\..*$gdb_prompt " {
> +			if {[string equal $full "source"]} {
> +			    pass $tst
> +			} else {
> +			    faill $tst
> +			}
> +		    }
> +		    -re "missing argument for \"-$full\".*$gdb_prompt " {
> +			pass $tst
> +		    }
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete unique function name"
> +    send_gdb "break -function mai\t"
> +    gdb_test_multiple "" $tst {
> +	"break -function mai\\\x07n" {
> +	    send_gdb "\n"
> +	    gdb_test "" ".*Breakpoint \[0-9\]+.*" $tst
> +	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +	}
> +    }
> +
> +    set tst "complete non-unique function name"
> +    send_gdb "break -function myfunc\t"
> +    gdb_test_multiple "" $tst {
> +	"break -function myfunc\\\x07tion" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		-re "\\\x07\r\nmyfunction\[ \t\]+myfunction2\[ \t\]+myfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
> +		    gdb_test "2" ".*Breakpoint \[0-9\]+.*" $tst
> +		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete non-existant function name"
> +    send_gdb "break -function foo\t"
> +    gdb_test_multiple "" $tst {
> +	"break -function foo\\\x07" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		-re "\\\x07\\\x07" {
> +		    send_gdb "\n"
> +		    gdb_test "" {Function "foo" not defined.} $tst
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete unique file name"
> +    send_gdb "break -source 3ex\t"
> +    gdb_test_multiple "" $tst {
> +	"break -source 3explicit.c " {
> +	    send_gdb "\n"
> +	    gdb_test "" \
> +		{Source filename requires function, label, or line offset.} $tst
> +	}
> +    }
> +
> +    set tst "complete non-unique file name"
> +    send_gdb "break -source exp\t"
> +    gdb_test_multiple "" $tst {
> +	"break -source exp\\\x07licit" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+\r\n$gdb_prompt" {
> +		    send_gdb "\n"
> +		    gdb_test "" \
> +			{Source filename requires function, label, or line offset.} \
> +			$tst
> +		}
> +	    }
> +	}
> +
> +	"break -source exp\\\x07l" {
> +	    # This pattern may occur when glibc debuginfo is installed.
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+expl.*\r\n$gdb_prompt" {
> +		    send_gdb "\n"
> +		    gdb_test "" \
> +			{Source filename requires function, label, or line offset.} \
> +			$tst
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete non-existant file name"
> +    send_gdb "break -source foo\t"
> +    gdb_test_multiple "" $tst {
> +	"break -source foo" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		"\\\x07\\\x07" {
> +		    send_gdb "\n"
> +		    gdb_test "" \
> +			{Source filename requires function, label, or line offset.} \
> +			$tst
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete filename and unique function name"
> +    send_gdb "break -source explicit.c -function ma\t"
> +    gdb_test_multiple "" $tst {
> +	"break -source explicit.c -function main " {
> +	    send_gdb "\n"
> +	    gdb_test "" ".*Breakpoint .*" $tst
> +	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +	}
> +    }
> +
> +    set tst "complete filename and non-unique function name"
> +    send_gdb "break -so 3explicit.c -func myfunc\t"
> +    gdb_test_multiple "" $tst {
> +	"break -so 3explicit.c -func myfunc\\\x07tion" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		-re "\\\x07\r\nmyfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
> +		    gdb_test "3" ".*Breakpoint \[0-9\]+.*" $tst
> +		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete filename and non-existant function name"
> +    send_gdb "break -sou 3explicit.c -fun foo\t"
> +    gdb_test_multiple "" $tst {
> +	"break -sou 3explicit.c -fun foo\\\x07" {
> +	    send_gdb "\t\t"
> +	    gdb_test_multiple "" $tst {
> +		"\\\x07\\\x07" {
> +		    send_gdb "\n"
> +		    gdb_test "" \
> +			{Function "foo" not defined in "3explicit.c".} $tst
> +		}
> +	    }
> +	}
> +    }
> +
> +    set tst "complete filename and function reversed"
> +    send_gdb "break -func myfunction4 -source 3ex\t"
> +    gdb_test_multiple "" $tst {
> +	"break -func myfunction4 -source 3explicit.c " {
> +	    send_gdb "\n"
> +	    gdb_test "" "Breakpoint \[0-9\]+.*" $tst
> +	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +	}
> +    }
> +
> +    # NOTE: We don't bother testing more elaborate combinations of options,
> +    # such as "-func main -sour 3ex\t" (main is defined in explicit.c).  The
> +    # completer cannot handle these yet.
> +
> +    # Test pending explicit breakpoints
> +    gdb_exit
> +    gdb_start
> +
> +    set tst "pending invalid conditional explicit breakpoint"
> +    if {![gdb_breakpoint "-func myfunction if foofoofoo == 1" \
> +	      allow-pending]} {
> +	fail "set $tst"
> +    } else {
> +	gdb_test "info break" ".*PENDING.*myfunction if foofoofoo == 1.*" $tst
> +    }
> +
> +    gdb_exit
> +    gdb_start
> +
> +    set tst "pending valid conditional explicit breakpoint"
> +    if {![gdb_breakpoint "-func myfunction if arg == 0" \
> +	      allow-pending]} {
> +	fail "set $tst"
> +    } else {
> +	gdb_test "info break" ".*PENDING.*myfunction if arg == 0" $tst
> +
> +	gdb_load [standard_output_file $exefile]
> +	gdb_test "info break" \
> +	    ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" \
> +	    "$tst resolved"
> +    }
> +
> +    # Test interaction of condition command and explicit linespec conditons.
> +    gdb_exit
> +    gdb_start
> +    gdb_load [standard_output_file $exefile]
> +
> +    set tst "condition_command overrides explicit linespec condition"
> +    if {![runto main]} {
> +	fail $tst
> +    } else {
> +	if {![gdb_breakpoint "-func myfunction if arg == 1"]} {
> +	    fail "set breakpoint with condition 'arg == 1'"
> +	} else {
> +	    gdb_test_no_output "cond 2 arg == 0" \
> +		"set new breakpoint condition for explicit linespec"
> +
> +	    gdb_continue_to_breakpoint $tst $location(normal)
> +	}
> +    }
> +
> +    gdb_test "cond 2" [string_to_regexp "Breakpoint 2 now unconditional."] \
> +	"clear condition for explicit breakpoint"
> +    set tst "info break of cleared condition of explicit breakpoint"
> +    gdb_test_multiple "info break" $tst {
> +	-re ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" {
> +	    fail $tst
> +	}
> +	-re ".*in myfunction at .*$srcfile:.*$gdb_prompt $" {
> +	    pass $tst
> +	}
> +    }
> +}
> +
> +namespace delete $testfile
> diff --git a/gdb/testsuite/gdb.linespec/explicit2.c b/gdb/testsuite/gdb.linespec/explicit2.c
> new file mode 100644
> index 0000000..218cccb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit2.c
> @@ -0,0 +1,24 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +extern int myfunction3 (int arg);
> +
> +int
> +myfunction2 (int arg)
> +{
> +  return myfunction3 (arg);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp
> index 019312c..c220241 100644
> --- a/gdb/testsuite/gdb.linespec/ls-errs.exp
> +++ b/gdb/testsuite/gdb.linespec/ls-errs.exp
> @@ -49,11 +49,16 @@ array set error_messages {
>      invalid_var_or_func_f \
>  	"Undefined convenience variable or function \"%s\" not defined in \"%s\"."
>      invalid_label "No label \"%s\" defined in function \"%s\"."
> +    invalid_parm "invalid linespec argument, \"%s\""
>      invalid_offset "No line %d in the current file."
>      invalid_offset_f "No line %d in file \"%s\"."
> +    malformed_line_offset "malformed line offset: \"%s\""
> +    source_incomplete \
> +	"Source filename requires function, label, or line offset."
>      unexpected "malformed linespec error: unexpected %s"
>      unexpected_opt "malformed linespec error: unexpected %s, \"%s\""
>      unmatched_quote "unmatched quote"
> +    garbage "Garbage '%s' at end of command"
>  }
>  
>  # Some commonly used whitespace tests around ':'.
> @@ -80,6 +85,7 @@ foreach x $invalid_offsets {
>  	incr offset 16
>      }
>      test_break $x invalid_offset $offset
> +    test_break "-line $x" invalid_offset $offset
>  }
>  
>  # Test offsets with trailing tokens w/ and w/o spaces.
> @@ -91,13 +97,17 @@ foreach x $spaces {
>  
>  foreach x {1 +1 +100 -10} {
>      test_break "3 $x" unexpected_opt "number" $x
> +    test_break "-line 3 $x" garbage $x
>      test_break "+10 $x" unexpected_opt "number" $x
> +    test_break "-line +10 $x" garbage $x
>      test_break "-10 $x" unexpected_opt "number" $x
> +    test_break "-line -10 $x" garbage $x
>  }
>  
> -test_break "3 foo" unexpected_opt "string" "foo"
> -test_break "+10 foo" unexpected_opt "string" "foo"
> -test_break "-10 foo" unexpected_opt "string" "foo"
> +foreach x {3 +10 -10} {
> +    test_break "$x foo" unexpected_opt "string" "foo"
> +    test_break "-line $x foo" garbage "foo"
> +}
>  
>  # Test invalid linespecs starting with filename.
>  foreach x [list "this_file_doesn't_exist.c" \
> @@ -113,6 +123,13 @@ foreach x [list "this_file_doesn't_exist.c" \
>      # Remove any quoting from FILENAME for the error message.
>      test_break "$x:3" invalid_file [string trim $x \"']
>  }
> +foreach x [list "this_file_doesn't_exist.c" \
> +	       "this file has spaces.c" \
> +	       "file::colons.c" \
> +	       "'file::colons.c'"] {
> +    test_break "-source $x -line 3" \
> +	invalid_file [string trim $x \"']
> +}
>  
>  # Test unmatched quotes.
>  foreach x {"\"src-file.c'" "'src-file.c"} {
> @@ -123,7 +140,11 @@ test_break $srcfile invalid_function $srcfile
>  foreach x {"foo" " foo" " foo "} {
>      # Trim any leading/trailing whitespace for error messages.
>      test_break "$srcfile:$x" invalid_function_f [string trim $x] $srcfile
> +    test_break "-source $srcfile -function $x" \
> +	invalid_function_f [string trim $x] $srcfile
>      test_break "$srcfile:main:$x" invalid_label [string trim $x] "main"
> +    test_break "-source $srcfile -function main -label $x" \
> +	invalid_label [string trim $x] "main"
>  }
>  
>  foreach x $spaces {
> @@ -133,20 +154,26 @@ foreach x $spaces {
>  
>  test_break "${srcfile}::" invalid_function "${srcfile}::"
>  test_break "$srcfile:3 1" unexpected_opt "number" "1"
> +test_break "-source $srcfile -line 3 1" garbage "1"
>  test_break "$srcfile:3 +100" unexpected_opt "number" "+100"
> +test_break "-source $srcfile -line 3 +100" garbage "+100"
>  test_break "$srcfile:3 -100" unexpected_opt "number" "-100"
>  test_break "$srcfile:3 foo" unexpected_opt "string" "foo"
> +test_break "-source $srcfile -line 3 foo" garbage "foo"
>  
>  foreach x $invalid_offsets {
>      test_break "$srcfile:$x" invalid_offset_f $x $srcfile
>      test_break "\"$srcfile:$x\"" invalid_offset_f $x $srcfile
>      test_break "'$srcfile:$x'" invalid_offset_f $x $srcfile
> +    test_break "-source $srcfile -line $x" invalid_offset_f $x $srcfile
>  }
> +test_break "-source $srcfile -line -x" malformed_line_offset "-x"
>  
>  # Test invalid filespecs starting with function.
>  foreach x {"foobar" "foo::bar" "foo.bar" "foo ." "foo bar" "foo 1" \
>  	       "foo 0" "foo +10" "foo -10" "foo +100" "foo -100"} {
>      test_break $x invalid_function $x
> +    test_break "-function \"$x\"" invalid_function $x
>  }
>  
>  foreach x $spaces {
> @@ -155,13 +182,12 @@ foreach x $spaces {
>      test_break "main:here${x}" unexpected "end of input"
>  }
>  
> -test_break "main 3" invalid_function "main 3"
> -test_break "main +100" invalid_function "main +100"
> -test_break "main -100" invalid_function "main -100"
> -test_break "main foo" invalid_function "main foo"
> -
>  foreach x {"3" "+100" "-100" "foo"} {
> +    test_break "main 3" invalid_function "main 3"
> +    test_break "-function \"main $x\"" invalid_function "main $x"
>      test_break "main:here $x" invalid_label "here $x" "main"
> +    test_break "-function main -label \"here $x\"" \
> +	invalid_label "here $x" "main"
>  }
>  
>  foreach x {"if" "task" "thread"} {
> @@ -178,3 +204,6 @@ test_break "'main.c'+3" unexpected_opt "number" "+3"
>  set x {$zippo}
>  test_break $x invalid_var_or_func $x
>  test_break "$srcfile:$x" invalid_var_or_func_f $x $srcfile
> +
> +# Explicit linespec-specific tests
> +test_break "-source $srcfile" source_incomplete


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