This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [RFA 3/4] Explicit locations
- From: Keith Seitz <keiths at redhat dot com>
- To: Tom Tromey <tromey at redhat dot com>
- Cc: "gdb-patches at sourceware dot org ml" <gdb-patches at sourceware dot org>
- Date: Mon, 16 Sep 2013 11:48:04 -0700
- Subject: Re: [RFA 3/4] Explicit locations
- Authentication-results: sourceware.org; auth=none
- References: <514B9EAF dot 80705 at redhat dot com> <51C35B2C dot 2070502 at redhat dot com> <87ioyydcan dot fsf at fleche dot redhat dot com>
On 08/21/2013 01:22 PM, Tom Tromey wrote:
"Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> +/* An enumeration of the various things a user might
Keith> + attempt to complete for a location. */
Keith> +
Keith> +enum explicit_location_match_type
Keith> + {
Brace placement.
Fixed.
Keith> - if (oind >= argc)
Keith> + if (oind >= argc && !is_explicit)
Keith> error (_("-%s-insert: Missing <location>"),
Keith> dprintf ? "dprintf" : "break");
I think this can leak various xstdup'd strings, e.g.,
explicit.label_name.
Gah. That was messed up. I've reworked all this. Now we just keep the
pointers around and call a new function, explicit_to_event_location, to
create the actual struct event_location (which copies everything it
needs to). Python will need this function, too, when the time comes to
add explicit locations to that.
standard_output_file
It's best not to refer to objdir if at all possible.
All fixed.
Keith
PS. One small note: I am not reposting the doc changes since those have
not changed and are already approved.
ChangeLog
2013-09-13 Keith Seitz <keiths@redhat.com>
* breakpoint.c (strace_command): Update to handle non-linespec
locations.
* completer.c: Include locations.h.
(enum match_type): New enum.
(location_completer): Rename to ...
(linespec_completer): ... this.
(collect_explicit_location_matches): New function.
(explicit_location_completer): New function.
(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): Likewise.
(find_toplevel_char): Likewise.
(linespec_parse_line_offset): Export.
If the first character of the input is not a digit,
throw an error.
(get_gdb_linespec_parser_quote_characters): New function.
* linespec.h (linespec_parse_line_offset): Declare.
(location_completer): Declare.
(get_gdb_linespec_parser_quote_characters): Declare.
(is_ada_operator): Likewise.
(find_toplevel_char): Likewise.
(linespec_lexer_lex_keyword): Likewise.
* locations.c: Include cli/cli-utils.h, probe.h, and ctype.h.
(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.
* locations.h (explicit_to_event_location): Declare.
(string_to_event_location): Declare.
(string_to_explicit_location): Declare.
* mi/mi-cmd-break.c: Include linespec.h.
(mi_cmd_break_insert): Handle explicit locations.
* probe.c (parse_probes): Handle explicit locations.
testsuite/ChangeLog
2013-09-13 Keith Seitz <keiths@redhat.com>
* gdb.base/save-bp.exp: Add tests for address locations
and explicit locations, pending and not-pending, with and
without conditions, including resolved pending breakpoints.
* 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.
* gdb.mi/mi-break.exp: Likewise.
* gdb.mi/mi-dprintf.exp: Use variable to track tokens in commands.
Add explicit location tests.
* lib/mi-support.exp (mi_create_breakpoint): Add support
for conditions.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index af6a1b4..23e7c7f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -15284,11 +15284,17 @@ strace_command (char *arg, int from_tty)
/* Decide if we are dealing with a static tracepoint marker (`-m'),
or with a normal static tracepoint. */
if (arg && strncmp (arg, "-m", 2) == 0 && isspace (arg[2]))
- ops = &strace_marker_breakpoint_ops;
+ {
+ ops = &strace_marker_breakpoint_ops;
+ location = new_event_location (EVENT_LOCATION_LINESPEC);
+ EVENT_LOCATION_LINESPEC (location) = xstrdup (arg);
+ }
else
- ops = &tracepoint_breakpoint_ops;
+ {
+ ops = &tracepoint_breakpoint_ops;
+ location = string_to_event_location (&arg, current_language);
+ }
- location = string_to_event_location (&arg, current_language);
back_to = make_cleanup (delete_event_location, location);
copy_location = *location;
create_breakpoint (get_current_arch (),
diff --git a/gdb/completer.c b/gdb/completer.c
index e132651..bb484e2 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -25,6 +25,7 @@
#include "gdb_assert.h"
#include "exceptions.h"
#include "gdb_signals.h"
+#include "locations.h"
#include "cli/cli-decode.h"
@@ -41,6 +42,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,
@@ -173,7 +189,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
@@ -182,9 +198,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;
@@ -331,6 +347,169 @@ 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 WHICH. */
+
+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;
+ struct explicit_location *explicit = EVENT_LOCATION_EXPLICIT (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 which_explicit"));
+ }
+
+ return matches;
+}
+
+/* A convenience macro to (safely) back up P to the previous
+ word. */
+
+#define BACKUP(P,S) \
+ do \
+ { \
+ while ((P) > (S) && isspace (*(P))) \
+ --(P); \
+ for (; (P) > (S) && !isspace ((P)[-1]); --(P)) \
+ ; \
+ } \
+ while (0)
+
+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 = word;
+ BACKUP (p, text);
+
+ if (*p == '-')
+ {
+ size_t len = strlen (word);
+
+ /* Completing on option name. */
+ if (strncmp (word, "source", len) == 0)
+ VEC_safe_push (char_ptr, matches, xstrdup ("source"));
+ else if (strncmp (word, "function", len) == 0)
+ VEC_safe_push (char_ptr, matches, xstrdup ("function"));
+ else if (*word == 'l')
+ {
+ if (strncmp (word, "line", len) == 0)
+ VEC_safe_push (char_ptr, matches, xstrdup ("line"));
+ if (strncmp (word, "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 = EVENT_LOCATION_EXPLICIT (location);
+
+ /* Backup P to the previous word, which should be the option
+ the user is attempting to complete. */
+ offset = word - p;
+ end = --p;
+ BACKUP (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;
+ }
+
+ /* 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 (©, current_language, 1);
+ if (location != NULL)
+ {
+ matches = explicit_location_completer (ignore, location, text, word);
+ delete_event_location (location);
+ }
+ 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. */
@@ -668,16 +847,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 != NULL)
list = (*c->completer) (c, p, word);
}
@@ -743,14 +912,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 != NULL)
list = (*c->completer) (c, p, word);
}
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 9d99eb4..8afba15 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -354,8 +354,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. */
@@ -405,7 +403,7 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
/* Does P represent one of the keywords? If so, return
the keyword. If not, return NULL. */
-static const char *
+const char *
linespec_lexer_lex_keyword (const char *p)
{
int i;
@@ -431,7 +429,7 @@ linespec_lexer_lex_keyword (const char *p)
/* Does STRING represent an Ada operator? If so, return the length
of the decoded operator name. If not, return 0. */
-static int
+int
is_ada_operator (const char *string)
{
const struct ada_opname_map *mapping;
@@ -1144,7 +1142,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;
@@ -1558,9 +1556,10 @@ source_file_not_found_error (const char *name)
/* Parse and return a line offset in STRING. */
-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 == '+')
@@ -1574,6 +1573,9 @@ linespec_parse_line_offset (const char *string)
++string;
}
+ if (!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;
@@ -3916,3 +3918,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 f62dc2e..efdb1d1 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -152,6 +152,36 @@ extern struct symtabs_and_lines decode_line_with_current_source (char *, int);
extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
+/* Parse a line offset from STRING. */
+
+extern struct line_offset linespec_parse_line_offset (const char *string);
+
+/* A completion handler for locations. */
+
+VEC (char_ptr) *location_completer (struct cmd_list_element *ignore,
+ const char *text, const char *word);
+
+/* 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);
+
+/* Does P represent one of the keywords? If so, return
+ the keyword. If not, return NULL. */
+
+extern const char *linespec_lexer_lex_keyword (const char *p);
+
/* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
advancing EXP_PTR past any parsed text. */
diff --git a/gdb/locations.c b/gdb/locations.c
index 478318e..6ba2530 100644
--- a/gdb/locations.c
+++ b/gdb/locations.c
@@ -23,6 +23,10 @@
#include "symtab.h"
#include "language.h"
#include "linespec.h"
+#include "cli/cli-utils.h"
+#include "probe.h"
+
+#include <ctype.h>
/* Initialize the given explicit location. */
@@ -103,6 +107,55 @@ copy_event_location (const struct event_location *src)
return dst;
}
+/* Return a struct event_location with the given explicit location.
+ The returned event_location is malloc'd and should be freed with
+ delete_event_location. */
+
+struct event_location *
+explicit_to_event_location (const struct explicit_location *explicit)
+{
+ struct event_location *location;
+ struct cleanup *back_to;
+
+ location = new_event_location (EVENT_LOCATION_EXPLICIT);
+ back_to = make_cleanup (delete_event_location, location);
+
+ if (explicit->source_filename != NULL)
+ {
+ /* Error check -- we must have one of the other
+ parameters specified. */
+ if (explicit->function_name == NULL
+ && explicit->label_name == NULL
+ && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
+ error (_("Source filename requires function, label, or "
+ "line offset."));
+
+ EVENT_LOCATION_EXPLICIT (location)->source_filename
+ = xstrdup (explicit->source_filename);
+ }
+
+ if (explicit->function_name != NULL)
+ {
+ EVENT_LOCATION_EXPLICIT (location)->function_name
+ = xstrdup (explicit->function_name);
+ }
+
+ if (explicit->label_name != NULL)
+ {
+ EVENT_LOCATION_EXPLICIT (location)->label_name
+ = xstrdup (explicit->label_name);
+ }
+
+ if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ {
+ EVENT_LOCATION_EXPLICIT (location)->line_offset
+ = explicit->line_offset;
+ }
+
+ discard_cleanups (back_to);
+ return location;
+}
+
/* Free LOCATION and any associated data. */
void
@@ -166,6 +219,226 @@ event_location_to_string (const struct event_location *location)
return result;
}
+/* 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')
+ {
+ /* 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);
+ 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;
+}
+
+/* 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. */
+
+struct event_location *
+string_to_explicit_location (const char **argp,
+ const struct language_defn *language,
+ int dont_throw)
+{
+ /* It is assumed that input beginning with '-' and a non-digit
+ character is an explicit location. */
+ if (argp != NULL && *argp != NULL)
+ {
+ const char *copy, *orig;
+
+ /* Skip past any probe arguments. */
+ orig = copy = *argp;
+ if (probe_linespec_to_ops (©) != NULL)
+ *argp = copy;
+
+ if ((*argp[0] == '-' && isalpha ((*argp)[1])))
+ {
+ char *s, *str;
+ struct cleanup *cleanup;
+ struct event_location *location;
+
+ location = new_event_location (EVENT_LOCATION_EXPLICIT);
+ 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);
+
+ /* Skip any whitespace. */
+ *argp = skip_spaces_const (*argp);
+
+ /* Get the argument string. */
+ oarg = explicit_location_lex_one (argp, language);
+
+ /* Skip any whitespace. */
+ *argp = skip_spaces_const (*argp);
+
+ /* Use the length of the option to allow abbreviations. */
+ len = strlen (opt);
+
+ /* All options have a required argument. */
+ if (strncmp (opt, "-source", len) == 0)
+ EVENT_LOCATION_EXPLICIT (location)->source_filename = oarg;
+ else if (strncmp (opt, "-function", len) == 0)
+ EVENT_LOCATION_EXPLICIT (location)->function_name = oarg;
+ else if (strncmp (opt, "-line", len) == 0)
+ {
+ if (oarg != NULL)
+ {
+ volatile struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ EVENT_LOCATION_EXPLICIT (location)->line_offset
+ = linespec_parse_line_offset (oarg);
+ }
+
+ xfree (oarg);
+ if (e.reason < 0 && !dont_throw)
+ throw_exception (e);
+ }
+ }
+ else if (strncmp (opt, "-label", len) == 0)
+ EVENT_LOCATION_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
+ {
+ /* Trailing garbage. This will be handled by
+ one of the callers. */
+ *argp = start;
+ break;
+ }
+
+ /* 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);
+ }
+
+ discard_cleanups (cleanup);
+
+ /* One special error check: If a source filename was given
+ without offset, function, or label, issue an error. */
+ if (EVENT_LOCATION_EXPLICIT (location)->source_filename != NULL
+ && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
+ && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
+ && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
+ == LINE_OFFSET_UNKNOWN)
+ && !dont_throw)
+ error (_("Source filename requires function, label, or "
+ "line offset."));
+
+ /* A valid explicit location was constructed. Save a copy
+ of the parsed input and save any unparsed input (which might
+ contain a condition, thread, or task expression). */
+ str = savestring (orig, *argp - orig);
+ s = remove_trailing_whitespace (str, str + (*argp - orig));
+ *s = '\0';
+ EVENT_LOCATION_SAVE_SPEC (location) = str;
+ return location;
+ }
+ }
+
+ /* Not an explicit location. */
+ return NULL;
+}
+
/* Parse the user input in *STRINGP and turn it into a struct
event_location, advancing STRINGP past any parsed input.
Return value is malloc'd. */
@@ -188,12 +461,27 @@ string_to_event_location (char **stringp,
}
else
{
- location = new_event_location (EVENT_LOCATION_LINESPEC);
+ const char *arg;
- if (*stringp != NULL)
+ /* Next, try an explicit location. */
+ arg = *stringp;
+ location = string_to_explicit_location (&arg, language, 0);
+ if (location == NULL)
+ {
+ /* The input was not a valid explicit location. It must be
+ a linespec. */
+ location = new_event_location (EVENT_LOCATION_LINESPEC);
+ if (*stringp != NULL)
+ {
+ EVENT_LOCATION_LINESPEC (location) = xstrdup (*stringp);
+ *stringp += strlen (*stringp);
+ }
+ }
+ else
{
- EVENT_LOCATION_LINESPEC (location) = xstrdup (*stringp);
- *stringp += strlen (*stringp);
+ /* It was a valid explicit location. Advance STRINGP to
+ the end of input. */
+ *stringp = (char *) arg;
}
}
diff --git a/gdb/locations.h b/gdb/locations.h
index f8ac807..4823e1a 100644
--- a/gdb/locations.h
+++ b/gdb/locations.h
@@ -137,6 +137,13 @@ extern struct event_location *
extern struct event_location *
copy_event_location (const struct event_location *src);
+/* Return a struct event_location with the given explicit location.
+ The returned event_location is malloc'd and should be freed with
+ delete_event_location. */
+
+extern struct event_location *
+ explicit_to_event_location (const struct explicit_location *explicit);
+
/* Initialize the given LOCATION. */
extern void initialize_event_location (struct event_location *location,
@@ -162,4 +169,32 @@ extern struct event_location *
/* A convenience function for testing for unset locations. */
extern int event_location_empty_p (const struct event_location *location);
+
+/* Attempt to convert the input string in *ARGP into an event location.
+ ARGP is advanced past any processed input. Returns a event_location
+ (malloc'd) if an event location was successfully found in *ARGP,
+ NULL otherwise.
+
+ This function may call error() if *ARGP looks like properly formed,
+ but invalid, input, e.g., if it is called with missing argument parameters
+ or invalid options. */
+
+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);
#endif /* LOCATIONS_H */
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index e002f50..55630cc 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -32,6 +32,7 @@
#include "mi-cmd-break.h"
#include "language.h"
#include "locations.h"
+#include "linespec.h"
#include "gdb_obstack.h"
#include <ctype.h>
@@ -183,6 +184,8 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
enum bptype type_wanted;
struct event_location *location;
struct breakpoint_ops *ops;
+ int is_explicit = 0;
+ struct explicit_location explicit;
char *extra_string = NULL;
enum opt
@@ -190,6 +193,8 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
TRACEPOINT_OPT,
+ EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
+ EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT
};
static const struct mi_opt opts[] =
{
@@ -201,6 +206,10 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
{"f", PENDING_OPT, 0},
{"d", DISABLE_OPT, 0},
{"a", TRACEPOINT_OPT, 0},
+ {"s", EXPLICIT_SOURCE_OPT, 1},
+ {"m", EXPLICIT_FUNC_OPT, 1},
+ {"l", EXPLICIT_LABEL_OPT, 1},
+ {"o", EXPLICIT_LINE_OPT, 1},
{ 0, 0, 0 }
};
@@ -209,6 +218,8 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
int oind = 0;
char *oarg;
+ initialize_explicit_location (&explicit);
+
while (1)
{
int opt = mi_getopt ("-break-insert", argc, argv,
@@ -241,16 +252,31 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
case TRACEPOINT_OPT:
tracepoint = 1;
break;
+ case EXPLICIT_SOURCE_OPT:
+ is_explicit = 1;
+ explicit.source_filename = oarg;
+ break;
+ case EXPLICIT_FUNC_OPT:
+ is_explicit = 1;
+ explicit.function_name = oarg;
+ break;
+ case EXPLICIT_LABEL_OPT:
+ is_explicit = 1;
+ explicit.label_name = oarg;
+ break;
+ case EXPLICIT_LINE_OPT:
+ is_explicit = 1;
+ explicit.line_offset = linespec_parse_line_offset (oarg);
+ break;
}
}
- if (oind >= argc)
+ if (oind >= argc && !is_explicit)
error (_("-%s-insert: Missing <location>"),
dprintf ? "dprintf" : "break");
- address = argv[oind];
if (dprintf)
{
- int format_num = oind + 1;
+ int format_num = is_explicit ? oind : oind + 1;
if (hardware || tracepoint)
error (_("-dprintf-insert: does not support -h or -a"));
@@ -259,11 +285,21 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
extra_string = mi_argv_to_format (argv + format_num, argc - format_num);
make_cleanup (xfree, extra_string);
+ address = argv[oind];
}
else
{
- if (oind < argc - 1)
- error (_("-break-insert: Garbage following <location>"));
+ if (is_explicit)
+ {
+ if (oind < argc)
+ error (_("-break-insert: Garbage following explicit location"));
+ }
+ else
+ {
+ if (oind < argc - 1)
+ error (_("-break-insert: Garbage following <location>"));
+ address = argv[oind];
+ }
}
/* Now we have what we need, let's insert the breakpoint! */
@@ -292,8 +328,12 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
ops = &bkpt_breakpoint_ops;
}
- location = string_to_event_location (&address, current_language);
+ if (is_explicit)
+ location = explicit_to_event_location (&explicit);
+ else
+ location = string_to_event_location (&address, current_language);
make_cleanup (delete_event_location, location);
+
create_breakpoint (get_current_arch (), location, condition, thread,
extra_string,
0 /* condition and thread are valid. */,
diff --git a/gdb/probe.c b/gdb/probe.c
index 830d65c..a2474ac 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -42,19 +42,19 @@ struct symtabs_and_lines
parse_probes (struct event_location *location,
struct linespec_result *canonical)
{
- char *arg_start, *arg_end, *arg;
+ char *arg_end, *arg;
char *objfile_name = NULL, *provider = NULL, *name, *p;
struct cleanup *cleanup;
struct symtabs_and_lines result;
struct objfile *objfile;
struct program_space *pspace;
const struct probe_ops *probe_ops;
- const char *cs;
+ const char *arg_start, *cs;
result.sals = NULL;
result.nelts = 0;
- arg_start = EVENT_LOCATION_LINESPEC (location);
+ arg_start = event_location_to_string (location);
cs = arg_start;
probe_ops = probe_linespec_to_ops (&cs);
@@ -171,7 +171,8 @@ parse_probes (struct event_location *location,
= savestring (arg_start, arg_end - arg_start);
}
- EVENT_LOCATION_LINESPEC (location) = arg_end;
+ if (EVENT_LOCATION_TYPE (location) == EVENT_LOCATION_LINESPEC)
+ EVENT_LOCATION_LINESPEC (location) = arg_end;
do_cleanups (cleanup);
return result;
diff --git a/gdb/testsuite/gdb.base/save-bp.exp b/gdb/testsuite/gdb.base/save-bp.exp
index 64df0f7..05a2cf2 100644
--- a/gdb/testsuite/gdb.base/save-bp.exp
+++ b/gdb/testsuite/gdb.base/save-bp.exp
@@ -27,6 +27,8 @@ if ![runto_main] {
# does not interfere with our testing.
delete_breakpoints
+set savefile [standard_output_file "bps"]
+
# Insert a bunch of breakpoints... The goal is to create breakpoints
# that we are going to try to save in a file and then reload. So
# try to create a good variety of them.
@@ -45,11 +47,14 @@ set loc_bp5 [gdb_get_line_number "with commands"]
gdb_breakpoint ${srcfile}:${loc_bp5}
gdb_test "commands\nsilent\nend" "End with.*" "add breakpoint commands"
+gdb_breakpoint "*break_me"
+
gdb_test "dprintf ${srcfile}:${loc_bp5},\"At foo entry\\n\"" "Dprintf .*"
# Now, save the breakpoints into a file...
-remote_file host delete "bps"
-gdb_test "save breakpoint bps"
+remote_file host delete $savefile
+gdb_test "save breakpoints $savefile" "Saved to file '$savefile'." \
+ "save breakpoints simple"
# Now start a new debugger session...
clean_restart $testfile
@@ -62,10 +67,172 @@ if ![runto_main] {
delete_breakpoints
# ... and restore the breakpoints.
-gdb_test "source bps"
+gdb_test "source $savefile" ".*" "source in saved breakpoints"
# Now, verify that all breakpoints have been created correctly...
set bp_row_start "\[0-9\]+ +breakpoint +keep +y +0x\[0-9a-f\]+ +in"
set dprintf_row_start "\[0-9\]+ +dprintf +keep +y +0x\[0-9a-f\]+ +in"
-gdb_test "info break" \
- " *Num +Type +Disp +Enb +Address +What\r\n$bp_row_start break_me at .*$srcfile:\[0-9\]+\r\n$bp_row_start main at .*$srcfile:$loc_bp2\r\n$bp_row_start main at .*$srcfile:$loc_bp3 +thread 1\r\n\[ \t]+stop only in thread 1\r\n$bp_row_start main at .*$srcfile:$loc_bp4\r\n\[ \t\]+stop only if i == 1( \\((host|target) evals\\))?\r\n$bp_row_start main at .*$srcfile:$loc_bp5\r\n\[ \t\]+silent\r\n$dprintf_row_start main at .*$srcfile:$loc_bp5\r\n\[ \t\]+printf.*"
+set expected " *Num +Type +Disp +Enb +Address +What\r\n"
+append expected "$bp_row_start break_me at .*$srcfile:\[0-9\]+\r\n"
+append expected "$bp_row_start main at .*$srcfile:$loc_bp2\r\n"
+append expected "$bp_row_start main at .*$srcfile:$loc_bp3 +thread 1\r\n\[ \t]+stop only in thread 1\r\n"
+append expected "$bp_row_start main at .*$srcfile:$loc_bp4\r\n\[ \t\]+stop only if i == 1( \\((host|target) evals\\))?\r\n"
+append expected "$bp_row_start main at .*$srcfile:$loc_bp5\r\n\[ \t\]+silent\r\n"
+append expected "$bp_row_start break_me at .*$srcfile:\[0-9\]+\r\n"
+append expected "$dprintf_row_start main at .*$srcfile:$loc_bp5\r\n\[ \t\]+printf.*"
+gdb_test "info break" $expected
+remote_file host delete "bps"
+
+# A special test for address locations.
+delete_breakpoints
+gdb_breakpoint "*break_me"
+gdb_test "save breakpoints $savefile" "Saved to file '$savefile'." \
+ "saved address breakpoint"
+
+set fd [open $savefile "r"]
+set line [gets $fd]
+if {[string equal $line "break *break_me"]} {
+ pass "address breakpoint saved properly"
+} else {
+ fail "address breakpoint saved properly"
+ send_log "got \"$line\"\n"
+}
+close $fd
+remote_file host delete $savefile
+
+# Test pending breakpoints.
+
+# Restart gdb without specifying the executable.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+# Create a location suitable for giving to the "break" command
+# made from the location (LOC) and condition (COND).
+
+proc locspec {loc cond} {
+ if {$cond == ""} {
+ return "$loc"
+ } else {
+ return "$loc if $cond"
+ }
+}
+
+# An array mapping locations and conditions.
+array set bp_list [list \
+ "break_me" "" \
+ "main" "i > 2" \
+ "-func main" "i == 0" \
+ "-source $srcfile -line $loc_bp2" "" \
+ "-source $srcfile -line $loc_bp3" "i == 3"]
+
+# Set a pending breakpoint at each location.
+foreach bp [array names bp_list] {
+ set spec [locspec $bp $bp_list($bp)]
+ gdb_breakpoint $spec "allow-pending"
+ set pending($spec) 0
+}
+
+# Save the breakpoints to a file.
+gdb_test "save breakpoints $savefile" "Saved to file '$savefile'." \
+ "save pending breakpoints"
+
+# Now read in the file, and verify the contents line-by-line.
+set fd [open $savefile "r"]
+while {[gets $fd line] >= 0} {
+ switch -regexp -- $line {
+ {^break .*$} {
+ set where [string range $line 6 end]
+ set pending([string trim $where]) 1
+ }
+
+ {^[ \t\n]*$} {
+ ;# empty line; ignore it
+ }
+ }
+}
+close $fd
+remote_file host delete $savefile
+
+# Check if all of our breakpoints were saved.
+foreach elem [array names bp_list] {
+ set spec [locspec $elem $bp_list($elem)]
+ if {$pending($spec) == 1} {
+ pass "save pending breakpoint \"$spec\""
+ unset pending($spec)
+ } else {
+ fail "save pending breakpoint \"$spec\""
+ }
+}
+
+# Now check if any extra breakpoints were in the file.
+if {[llength [array names pending]] == 0} {
+ pass "saved all pending breakpoints"
+} else {
+ fail "saved all pending breakpoints"
+ send_log "extra breakpoint locations = [array names pending]\n"
+}
+
+# Now load the executable and save and verify the breakpoints again.
+gdb_load [standard_output_file $testfile]
+gdb_test "save breakpoints $savefile" "Saved to file '$savefile'." \
+ "save resolved breakpoints"
+
+unset pending
+set fd [open $savefile "r"]
+while {[gets $fd line] >= 0} {
+ switch -regexp -- $line {
+ {^break .*$} {
+ set where [string trim [string range $line 6 end]]
+ set pending($where) ""
+ }
+
+ {^[\ \t]+condition \$bpnum .*$} {
+ set idx [string first {$bpnum } $line]
+ set cond [string trim \
+ [string range $line [expr {$idx + 7}] end]]
+ set pending($where) $cond
+ }
+ }
+}
+
+foreach actual [array names bp_list] {
+ set test "resolved breakpoint [locspec $actual $bp_list($actual)]"
+ if {[info exists pending($actual)]
+ && [string equal $bp_list($actual) $pending($actual)]} {
+ pass $test
+ unset pending($actual)
+ } else {
+ fail $test
+ }
+}
+
+close $fd
+remote_file host delete $savefile
+
+if {[llength [array names pending]] == 0} {
+ pass "saved all resolved breakpoints"
+} else {
+ fail "saved all resolved breakpoints"
+ send_log "extra breakpoint locations = [array names pending]\n"
+}
+delete_breakpoints
+
+# Test that empty linespecs are saved properly.
+clean_restart $testfile
+if {![runto_main]} {
+ perror "couldn't run to breakpoint"
+ return -1
+}
+gdb_test "next"
+
+delete_breakpoints
+gdb_breakpoint ""
+gdb_test "save breakpoints $savefile" "Saved to file '$savefile'." \
+ "save empty linespec breakpoint"
+gdb_test "shell cat $savefile" "break \\*0x.*" \
+ "empty linespec saved properly"
+remote_file host delete $savefile
+delete_breakpoints
+
+unset -nocomplain bp_list pending fd spec elem line test
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..2bb9291
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
@@ -0,0 +1,104 @@
+# 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/>.
+
+# 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
+}
+
+# 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
+}
+
+# Make sure variables are not already in use
+unset -nocomplain lineno location linespecs
+
+# Some locations used in this test
+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
+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]} {
+ 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)\\."
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..f31c72c
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,353 @@
+# 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/>.
+
+# 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
+}
+
+# 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
+}
+
+# Make sure variables are not already in use
+unset -nocomplain all_arguments lineno location linespecs
+
+# A list of all explicit linespec arguments.
+set all_arguments {"source" "function" "label" "line"}
+
+# Some locations used in this test
+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.
+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
+}
+
+# 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 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
+ }
+ }
+ }
+}
+
+
+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
+ }
+}
+
+unset -nocomplain lineno tst
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 b7ac212..b348d34 100644
--- a/gdb/testsuite/gdb.linespec/ls-errs.exp
+++ b/gdb/testsuite/gdb.linespec/ls-errs.exp
@@ -50,11 +50,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 ':'.
@@ -87,6 +92,7 @@ foreach x $invalid_offsets {
incr offset 16
}
add the_tests $x invalid_offset $offset
+ add the_tests "-line $x" invalid_offset $offset
}
# Test offsets with trailing tokens w/ and w/o spaces.
@@ -98,13 +104,17 @@ foreach x $spaces {
foreach x {1 +1 +100 -10} {
add the_tests "3 $x" unexpected_opt "number" $x
+ add the_tests "-line 3 $x" garbage $x
add the_tests "+10 $x" unexpected_opt "number" $x
+ add the_tests "-line +10 $x" garbage $x
add the_tests "-10 $x" unexpected_opt "number" $x
+ add the_tests "-line -10 $x" garbage $x
}
-add the_tests "3 foo" unexpected_opt "string" "foo"
-add the_tests "+10 foo" unexpected_opt "string" "foo"
-add the_tests "-10 foo" unexpected_opt "string" "foo"
+foreach x {3 +10 -10} {
+ add the_tests "$x foo" unexpected_opt "string" "foo"
+ add the_tests "-line $x foo" garbage "foo"
+}
# Test invalid linespecs starting with filename.
foreach x [list "this_file_doesn't_exist.c" \
@@ -120,6 +130,13 @@ foreach x [list "this_file_doesn't_exist.c" \
# Remove any quoting from FILENAME for the error message.
add the_tests "$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'"] {
+ add the_tests "-source $x -line 3" \
+ invalid_file [string trim $x \"']
+}
# Test unmatched quotes.
foreach x {"\"src-file.c'" "'src-file.c"} {
@@ -130,7 +147,11 @@ add the_tests $srcfile invalid_function $srcfile
foreach x {"foo" " foo" " foo "} {
# Trim any leading/trailing whitespace for error messages.
add the_tests "$srcfile:$x" invalid_function_f [string trim $x] $srcfile
+ add the_tests "-source $srcfile -function $x" \
+ invalid_function_f [string trim $x] $srcfile
add the_tests "$srcfile:main:$x" invalid_label [string trim $x] "main"
+ add the_tests "-source $srcfile -function main -label $x" \
+ invalid_label [string trim $x] "main"
}
foreach x $spaces {
@@ -140,20 +161,27 @@ foreach x $spaces {
add the_tests "${srcfile}::" invalid_function "${srcfile}::"
add the_tests "$srcfile:3 1" unexpected_opt "number" "1"
+add the_tests "-source $srcfile -line 3 1" garbage "1"
add the_tests "$srcfile:3 +100" unexpected_opt "number" "+100"
+add the_tests "-source $srcfile -line 3 +100" garbage "+100"
add the_tests "$srcfile:3 -100" unexpected_opt "number" "-100"
+add the_tests "-source $srcfile -line 3 -100" garbage "-100"
add the_tests "$srcfile:3 foo" unexpected_opt "string" "foo"
+add the_tests "-source $srcfile -line 3 foo" garbage "foo"
foreach x $invalid_offsets {
add the_tests "$srcfile:$x" invalid_offset_f $x $srcfile
add the_tests "\"$srcfile:$x\"" invalid_offset_f $x $srcfile
add the_tests "'$srcfile:$x'" invalid_offset_f $x $srcfile
+ add the_tests "-source $srcfile -line $x" invalid_offset_f $x $srcfile
}
+add the_tests "-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"} {
add the_tests $x invalid_function $x
+ add the_tests "-function \"$x\"" invalid_function $x
}
foreach x $spaces {
@@ -161,13 +189,12 @@ foreach x $spaces {
add the_tests "main:here${x}" unexpected "end of input"
}
-add the_tests "main 3" invalid_function "main 3"
-add the_tests "main +100" invalid_function "main +100"
-add the_tests "main -100" invalid_function "main -100"
-add the_tests "main foo" invalid_function "main foo"
-
foreach x {"3" "+100" "-100" "foo"} {
+ add the_tests "main $x" invalid_function "main $x"
+ add the_tests "-function \"main $x\"" invalid_function "main $x"
add the_tests "main:here $x" invalid_label "here $x" "main"
+ add the_tests "-function main -label \"here $x\"" \
+ invalid_label "here $x" "main"
}
foreach x {"if" "task" "thread"} {
@@ -185,6 +212,9 @@ set x {$zippo}
add the_tests $x invalid_var_or_func $x
add the_tests "$srcfile:$x" invalid_var_or_func_f $x $srcfile
+# Explicit linespec specific tests
+add the_tests "-source $srcfile" source_incomplete
+
# Run the tests
foreach linespec $the_tests(linespecs) {
gdb_test "break $linespec" $the_tests("$linespec")
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index d5d58c7..9a7b1d5 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -271,6 +271,95 @@ proc test_breakpoint_commands {} {
mi_expect_stop "exited-normally" "" "" "" "" "" "test hitting breakpoint with commands"
}
+# Test explicit breakpoints. These tests only test the MI portion of the
+# code. In-depth testing of explicit breakpoints is accomplished in
+# gdb.linespec tests.
+
+proc test_explicit_breakpoints {} {
+ global mi_gdb_prompt
+ global srcfile
+ global hex
+ global line_callee4_head line_callee4_body
+ global line_callee3_head line_callee3_body
+ global line_callee2_head line_callee2_body
+ global line_callee1_head line_callee1_body
+ global line_main_head line_main_body
+ global fullname
+
+ mi_delete_breakpoints
+
+ # First check mixed explicit/parsed linespecs.
+ mi_gdb_test "-break-insert -m main $srcfile:$line_callee3_head" \
+ ".*Garbage following explicit linespec"
+
+ # Insert some breakpoints and list them
+ # Also, disable some so they do not interfere with other tests
+ # Tests:
+ # -break-insert -t -m main
+ # -break-insert -t -s basics.c -m callee2
+ # -break-insert -t -s basics.c -o $line_callee3_head
+ # -break-insert -t -s srcfile -o $line_callee4_head
+ # -break-list
+
+ mi_create_breakpoint "-t -m main" 11 del main ".*$srcfile" \
+ $line_main_body $hex "insert temp explicit breakpoint at -m main"
+
+ mi_create_breakpoint "-t -s $srcfile -m callee2" 12 del \
+ callee2 ".*$srcfile" $line_callee2_body $hex \
+ "insert temp explicit breakpoint at -s $srcfile -m callee2"
+
+ mi_create_breakpoint "-t -s $srcfile -o $line_callee3_head" \
+ 13 del callee3 ".*$srcfile" $line_callee3_head $hex \
+ "insert temp explicit breakpoint at -s $srcfile -o $line_callee3_head"
+
+ mi_create_breakpoint \
+ "-t -s \"$srcfile\" -o $line_callee4_head" \
+ 14 del callee4 ".*$srcfile" $line_callee4_head $hex \
+ "insert temp explicit breakpoint at -s \"$srcfile\" -o $line_callee4_head"
+
+ set expected "\\\^done,BreakpointTable=\{nr_rows=\".\",nr_cols=\".\",hdr=\\\[\{width=\".*\",alignment=\".*\",col_name=\"number\",colhdr=\"Num\"\}.*colhdr=\"Type\".*colhdr=\"Disp\".*colhdr=\"Enb\".*colhdr=\"Address\".*colhdr=\"What\".*\\\],body=\\\["
+ append expected "bkpt=\{number=\"11\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"main\",file=\".*$srcfile\",${fullname},line=\"$line_main_body\",thread-groups=\\\[\"i1\"\\\],times=\"0\",original-location=\".*\"\}"
+ append expected ",bkpt=\{number=\"12\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"callee2\",file=\".*$srcfile\",${fullname},line=\"$line_callee2_body\",thread-groups=\\\[\"i1\"\\\],times=\"0\",original-location=\".*\"\}"
+ append expected ",bkpt=\{number=\"13\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"callee3\",file=\".*$srcfile\",${fullname},line=\"$line_callee3_head\",thread-groups=\\\[\"i1\"\\\],times=\"0\",original-location=\".*\"\}"
+ append expected ",bkpt=\{number=\"14\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"callee4\",file=\".*$srcfile\",${fullname},line=\"$line_callee4_head\",thread-groups=\\\[\"i1\"\\\],times=\"0\",original-location=\".*\"\}"
+ append expected "\\\]\}"
+ send_log "\nexpecting\n$expected\n"
+
+ mi_gdb_test "-break-list" $expected \
+ "list of explicit breakpoints"
+
+ mi_gdb_test "-break-delete" \
+ "\\^done" \
+ "delete temp breakpoints"
+
+ mi_create_breakpoint "-c \"intarg == 3\" -m callee2" \
+ 15 keep callee2 ".*$srcfile" $line_callee2_body $hex \
+ "insert explicit conditional breakpoint at -m callee2" \
+ "intarg == 3"
+
+ # mi_create_breakpoint cannot deal with displaying canonical
+ # linespecs.
+ mi_gdb_test \
+ "-break-insert -c \"foo == 3\" -s $srcfile -m main -l label" \
+ ".*No symbol \"foo\" in current context.*"
+
+ mi_gdb_test \
+ "-break-insert -s foobar.c -offset 3" \
+ ".*No source file named foobar.c.*"
+
+ mi_gdb_test \
+ "-break-insert -s $srcfile -m foobar" \
+ ".*Function \"foobar\" not defined in \"$srcfile\".*"
+
+ mi_gdb_test \
+ "-break-insert -s $srcfile -m main -l foobar" \
+ ".*No label \"foobar\" defined in function \"main\".*"
+
+ mi_gdb_test \
+ "-break-insert -s $srcfile" \
+ ".*Source filename requires function, label, or line offset.*"
+}
+
test_tbreak_creation_and_listing
test_rbreak_creation_and_listing
@@ -284,5 +373,7 @@ test_breakpoint_commands
test_abreak_creation
+test_explicit_breakpoints
+
mi_gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.mi/mi-dprintf.exp b/gdb/testsuite/gdb.mi/mi-dprintf.exp
index 812f149..46df97f 100644
--- a/gdb/testsuite/gdb.mi/mi-dprintf.exp
+++ b/gdb/testsuite/gdb.mi/mi-dprintf.exp
@@ -36,27 +36,35 @@ set dp_location1 [gdb_get_line_number "set dprintf 1 here"]
mi_run_to_main
-mi_gdb_test "1-dprintf-insert" \
- "1\\^error,msg=\"-dprintf-insert: Missing <location>\"" "mi insert without location"
+set i 0
+mi_gdb_test "[incr i]-dprintf-insert" \
+ "$i\\^error,msg=\"-dprintf-insert: Missing <location>\"" "mi insert without location"
-mi_gdb_test "2-dprintf-insert foo" \
- "2\\^error,msg=\"-dprintf-insert: Missing <format>\"" "mi insert breakpoint without format string"
+mi_gdb_test "[incr i]-dprintf-insert foo" \
+ "$i\\^error,msg=\"-dprintf-insert: Missing <format>\"" "mi insert breakpoint without format string"
-mi_gdb_test "3-dprintf-insert 29" \
- "3\\^error,msg=\"-dprintf-insert: Missing <format>\"" "mi insert second breakpoint without format string"
+mi_gdb_test "[incr i]-dprintf-insert 29" \
+ "$i\\^error,msg=\"-dprintf-insert: Missing <format>\"" "mi insert second breakpoint without format string"
mi_gdb_test "-break-insert main" ".*" "mi insert breakpoint main"
+
+mi_gdb_test "[incr i]-dprintf-insert -m main \"hello\"" \
+ "$i\\^done,bkpt={.*}" "explicit dprintf at main"
+
+mi_gdb_test "[incr i]-dprintf-insert -s $srcfile -o $dp_location1 \"hello\"" \
+ "$i\\^done,bkpt={.*}" "explicit breakpoint at $srcfile:$dp_location1"
+
mi_delete_breakpoints
-mi_gdb_test "4-dprintf-insert foo \"\\\"foobarbazqux\\\" At foo entry\\n\"" \
- "4\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*" "mi insert dprintf foo"
+mi_gdb_test "[incr i]-dprintf-insert foo \"\\\"foobarbazqux\\\" At foo entry\\n\"" \
+ "$i\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*" "mi insert dprintf foo"
-mi_gdb_test "5-dprintf-insert $dp_location1 \"arg=%d, g=%d\\n\" arg g" \
- "5\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \
+mi_gdb_test "[incr i]-dprintf-insert $dp_location1 \"arg=%d, g=%d\\n\" arg g" \
+ "$i\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \
"mi insert dprintf dp_location1"
-mi_gdb_test "6-break-info" \
- "6\\^done,BreakpointTable=\{nr_rows=\".\",nr_cols=\".\",hdr=\\\[\{width=\".*\",alignment=\".*\",col_name=\"number\",colhdr=\"Num\"\},\{width=\".*\",alignment=\".*\",col_name=\"type\",colhdr=\"Type\"\},\{width=\".*\",alignment=\".*\",col_name=\"disp\",colhdr=\"Disp\"\},\{width=\".*\",alignment=\".*\",col_name=\"enabled\",colhdr=\"Enb\"\},\{width=\".*\",alignment=\".*\",col_name=\"addr\",colhdr=\"Address\"\},\{width=\".*\",alignment=\".*\",col_name=\"what\",colhdr=\"What\"\}\\\],body=\\\[bkpt=\{number=\"3\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \
+mi_gdb_test "[incr i]-break-info" \
+ "$i\\^done,BreakpointTable=\{nr_rows=\".\",nr_cols=\".\",hdr=\\\[\{width=\".*\",alignment=\".*\",col_name=\"number\",colhdr=\"Num\"\},\{width=\".*\",alignment=\".*\",col_name=\"type\",colhdr=\"Type\"\},\{width=\".*\",alignment=\".*\",col_name=\"disp\",colhdr=\"Disp\"\},\{width=\".*\",alignment=\".*\",col_name=\"enabled\",colhdr=\"Enb\"\},\{width=\".*\",alignment=\".*\",col_name=\"addr\",colhdr=\"Address\"\},\{width=\".*\",alignment=\".*\",col_name=\"what\",colhdr=\"What\"\}\\\],body=\\\[bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \
"mi info dprintf"
mi_gdb_test "-break-insert $bp_location1" ".*" "mi insert breakpoint bp_location1"
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 86a0fd6..10d3839 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1203,11 +1203,14 @@ proc mi0_continue_to { bkptno func args file line test } {
}
# Creates a breakpoint and checks the reported fields are as expected
-proc mi_create_breakpoint { location number disp func file line address test } {
- verbose -log "Expecting: 222\\^done,bkpt=\{number=\"$number\",type=\"breakpoint\",disp=\"$disp\",enabled=\"y\",addr=\"$address\",func=\"$func\",file=\"$file\",fullname=\".*\",line=\"$line\",thread-groups=\\\[\".*\"\\\],times=\"0\",original-location=\".*\"\}"
- mi_gdb_test "222-break-insert $location" \
- "222\\^done,bkpt=\{number=\"$number\",type=\"breakpoint\",disp=\"$disp\",enabled=\"y\",addr=\"$address\",func=\"$func\",file=\"$file\",fullname=\".*\",line=\"$line\",thread-groups=\\\[\".*\"\\\],times=\"0\",original-location=\".*\"\}" \
- $test
+proc mi_create_breakpoint { location number disp func file line address test {cond ""} } {
+ set expected "222\\^done,bkpt=\{number=\"$number\",type=\"breakpoint\",disp=\"$disp\",enabled=\"y\",addr=\"$address\",func=\"$func\",file=\"$file\",fullname=\".*\",line=\"$line\",thread-groups=\\\[\".*\"\\\],"
+ if {[string length $cond]} {
+ append expected "cond=\"$cond\","
+ }
+ append expected "times=\"0\",original-location=\".*\"\}"
+ verbose -log "Expecting: $expected"
+ mi_gdb_test "222-break-insert $location" $expected $test
}
proc mi_list_breakpoints { expected test } {