aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog29
-rw-r--r--gdb/completer.c218
-rw-r--r--gdb/linespec.c25
-rw-r--r--gdb/linespec.h20
-rw-r--r--gdb/location.c208
-rw-r--r--gdb/location.h15
-rw-r--r--gdb/testsuite/ChangeLog13
-rw-r--r--gdb/testsuite/gdb.linespec/3explicit.c28
-rw-r--r--gdb/testsuite/gdb.linespec/cpexplicit.cc63
-rw-r--r--gdb/testsuite/gdb.linespec/cpexplicit.exp112
-rw-r--r--gdb/testsuite/gdb.linespec/explicit.c56
-rw-r--r--gdb/testsuite/gdb.linespec/explicit.exp406
-rw-r--r--gdb/testsuite/gdb.linespec/explicit2.c24
-rw-r--r--gdb/testsuite/gdb.linespec/ls-errs.exp57
-rw-r--r--gdb/testsuite/lib/gdb.exp6
15 files changed, 1238 insertions, 42 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 13d31a6..57717bd 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
2015-08-11 Keith Seitz <keiths@redhat.com>
+ * 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, is_ada_operator)
+ (find_toplevel_char): Export.
+ (linespec_parse_line_offset): Export.
+ 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.
+
+2015-08-11 Keith Seitz <keiths@redhat.com>
+
* break-catch-throw.c (re_set_exception_catchpoint): Convert
linespec into explicit location.
* breakpoint.c (create_overlay_breakpoint)
diff --git a/gdb/completer.c b/gdb/completer.c
index d1ebf67..7fc27b1 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -27,6 +27,7 @@
#include "reggroups.h"
#include "user-regs.h"
#include "arch-utils.h"
+#include "location.h"
#include "cli/cli-decode.h"
@@ -43,6 +44,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,
@@ -175,7 +191,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
@@ -184,9 +200,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;
@@ -333,6 +349,182 @@ 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 == '-')
+ {
+ /* Completing on option name. */
+ static const char *const keywords[] =
+ {
+ "source",
+ "function",
+ "line",
+ "label",
+ NULL
+ };
+
+ /* Skip over the '-'. */
+ ++p;
+
+ return complete_on_enum (keywords, p, p);
+ }
+ 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. */
@@ -688,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);
@@ -766,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 84e518f..ff8ae05 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;
@@ -3903,3 +3904,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 3985e5a..675c8d9 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -429,6 +429,196 @@ 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 or comma. */
+ if (*start == '-' || *start == '+')
+ {
+ while (*inp[0] != '\0' && *inp[0] != ',' && !isspace (*inp[0]))
+ ++(*inp);
+ }
+ 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 whitespace, '\0',
+ keyword, or ','. */
+ *inp = start;
+ while ((*inp)[0]
+ && (*inp)[0] != ','
+ && !(isspace ((*inp)[0])
+ || 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 *opt_cleanup, *oarg_cleanup;
+
+ /* 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);
+ opt_cleanup = make_cleanup (xfree, opt);
+
+ *argp = skip_spaces_const (*argp);
+
+ /* Get the argument string. */
+ oarg = explicit_location_lex_one (argp, language);
+ oarg_cleanup = make_cleanup (xfree, oarg);
+ *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)
+ {
+ EL_EXPLICIT (location)->line_offset
+ = linespec_parse_line_offset (oarg);
+ do_cleanups (oarg_cleanup);
+ do_cleanups (opt_cleanup);
+ 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]))
+ {
+ 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;
+ discard_cleanups (oarg_cleanup);
+ do_cleanups (opt_cleanup);
+ 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 pair was successfully processed;
+ oarg belongs to the explicit location, and opt should
+ be freed. */
+ discard_cleanups (oarg_cleanup);
+ do_cleanups (opt_cleanup);
+ }
+
+ /* 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 *
@@ -461,8 +651,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 3082d9e..31ae59a 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -203,6 +203,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/ChangeLog b/gdb/testsuite/ChangeLog
index 5fa6cdd..ae3a275 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,18 @@
2015-08-11 Keith Seitz <keiths@redhat.com>
+ * 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.
+ * lib/gdb.exp (capture_command_output): Regexp-escape `command'
+ before using in the matching pattern.
+ Clarify that `prefix' is a regular expression.
+
+2015-08-11 Keith Seitz <keiths@redhat.com>
+
* gdb.base/dprintf-pending.exp: Update dprintf "without format"
test.
Add tests for missing ",FMT" and ",".
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..344f1b0
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,406 @@
+# 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
+ }
+ }
+
+ # Test explicit "ranges." Make sure that using explicit
+ # locations doesn't alter the expected outcome.
+ gdb_test "list main" ".*" "list main 1"
+ set list_result [capture_command_output "list -,+" ""]
+ gdb_test "list main" ".*" "list main 2"
+ gdb_test "list -line -,-line +" [string_to_regexp $list_result]
+
+ # Ditto for the reverse (except that no output is expected).
+ gdb_test "list myfunction" ".*" "list myfunction 1"
+ gdb_test_no_output "list +,-"
+ gdb_test "list myfunction" ".*" "list myfunction 2"
+ gdb_test_no_output "list -line +, -line -"
+}
+
+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..9b30720 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,25 @@ 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" \
+ "file::colons.c" \
+ "'file::colons.c'"] {
+ test_break "-source $x -line 3" \
+ invalid_file [string trim $x \"']
+}
+
+# Test that option lexing stops at whitespace boundaries
+test_break "-source this file has spaces.c -line 3" \
+ invalid_file "this"
+
+test_break "-function function whitespace" \
+ invalid_function "function"
+
+test_break "-source $srcfile -function function whitespace" \
+ invalid_function_f "function" $srcfile
+
+test_break "-function main -label label whitespace" \
+ invalid_label "label" "main"
# Test unmatched quotes.
foreach x {"\"src-file.c'" "'src-file.c"} {
@@ -123,7 +152,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 +166,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 +194,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 +216,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
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index ad2ad6e..5ecef1a 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5552,14 +5552,16 @@ proc parse_args { argset } {
# number of items expected to be passed into the procedure...
}
-# Capture the output of COMMAND in a string ignoring PREFIX; return that string.
+# Capture the output of COMMAND in a string ignoring PREFIX (a regexp);
+# return that string.
+
proc capture_command_output { command prefix } {
global gdb_prompt
global expect_out
set output_string ""
gdb_test_multiple "$command" "capture_command_output for $command" {
- -re "${command}\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
+ -re "[string_to_regexp ${command}]\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
set output_string $expect_out(1,string)
}
}