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


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

[RFA 3/4] Explicit locations


Hi,

This purpose of this patch is to add functionality (and tests) to the CLI and MI for explicit locations.

I've pushed all the documentation into the last patch to make it easier to review (well, IMO).

Keith

ChangeLog
2013-03-21  Keith Seitz  <keiths@redhat.com>

	* cli/cli-cmds.c (edit_command): Permit explicit locations.
	(list_command): Likewise.
	* linespec.c (linespec_parse_line_offset): Export.
	If the first character of the input is not a digit,
	throw an error.
	(explicit_location_lex_one): New function.
	(string_to_explicit_location): New function.
	(string_to_event_location): Handle explicit locations.
	* linespec.h (linespec_parse_line_offset): Declare.
	* mi/mi-cmd-break.c (mi_cmd_break_insert): Handle explicit
	locations.

testsuite/ChangeLog
2013-03-21  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/cpexplicit.cc: New file.
	* gdb.linespec/cpexplicit.exp: New file.
	* gdb.linespec/explicit.c: New file.
	* gdb.linespec/explicit.exp: New file.
	* gdb.linespec/ls-errs.exp: Add explicit location tests.
	* gdb.mi/mi-break.exp: Likewise.
	* lib/mi-support.exp (mi_create_breakpoint): Add support
	for conditions.


diff --git a/gdb/linespec.c b/gdb/linespec.c
index 710fa21..f675625 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1560,9 +1560,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 == '+')
@@ -1576,6 +1577,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;
@@ -3892,6 +3896,228 @@ make_cleanup_destroy_linespec_result (struct linespec_result *ls)
   return make_cleanup (cleanup_linespec_result, ls);
 }
 
+/* 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')
+    {
+      int lexing_number = 0;
+
+      /* If quoted, skip to the ending quote.  */
+      if (strchr (linespec_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);
+	    }
+	}
+
+      /* Are we lexing a number?  */
+      if ((start[0] == '-' || start[0] == '+')
+	  && start[1] && isdigit (start[1]))
+	{
+	  /* The input is a relative offset.  */
+	  lexing_number = 1;
+
+	  /* Skip the +/-.  */
+	  ++(*inp);
+	}
+      else if (isdigit (*start))
+	lexing_number = 1;
+
+      /* If the input starts with '-', the string ends with the next
+	 whitespace.  */
+      if (*start == '-')
+	{
+	  while ((*inp)[0] && !isspace ((*inp)[0]))
+	    ++(*inp);
+	}
+      /* If lexing a number, stop at the first non-digit character.  */
+      else if (lexing_number)
+	{
+	  while ((*inp)[0] && isdigit ((*inp)[0]))
+	    ++(*inp);
+	}
+      /* Otherwise stop at the next occurrence of "SPACE -", '\0',
+	 keyword, or ','.  */
+      else
+	{
+	  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.
+
+   This function may call error() if *ARGP looks like properly formed input,
+   e.g., iif it is called with missing argument parameters or invalid
+   options.  */
+
+static struct event_location *
+string_to_explicit_location (const char **argp,
+			     const struct language_defn *language)
+{
+  /* 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 (&copy) != 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)
+		    {
+		      EVENT_LOCATION_EXPLICIT (location)->line_offset
+			= linespec_parse_line_offset (oarg);
+		      xfree (oarg);
+		    }
+		}
+	      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);
+		  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)
+		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))
+	    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.  */
@@ -3914,12 +4140,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);
+      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/linespec.h b/gdb/linespec.h
index fcfc2f5..ea8c416 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -190,4 +190,9 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
 extern struct event_location *
 	string_to_event_location (char **argp,
 				 const struct language_defn *langauge);
+
+/* Parse a line offset from STRING.  */
+
+extern struct line_offset linespec_parse_line_offset (const char *string);
+
 #endif /* defined (LINESPEC_H) */
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index d673878..3f5dcf6 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -105,12 +105,16 @@ mi_cmd_break_insert (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;
 
   enum opt
     {
       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[] =
   {
@@ -122,6 +126,10 @@ mi_cmd_break_insert (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 }
   };
 
@@ -130,6 +138,8 @@ mi_cmd_break_insert (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,
@@ -162,14 +172,38 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
 	case TRACEPOINT_OPT:
 	  tracepoint = 1;
 	  break;
+	case EXPLICIT_SOURCE_OPT:
+	  is_explicit = 1;
+	  explicit.source_filename = xstrdup (oarg);
+	  break;
+	case EXPLICIT_FUNC_OPT:
+	  is_explicit = 1;
+	  explicit.function_name = xstrdup (oarg);
+	  break;
+	case EXPLICIT_LABEL_OPT:
+	  is_explicit = 1;
+	  explicit.label_name = xstrdup (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 (_("-break-insert: Missing <location>"));
-  if (oind < argc - 1)
-    error (_("-break-insert: Garbage following <location>"));
-  address = argv[oind];
+  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!  */
   back_to = setup_breakpoint_reporting ();
@@ -186,8 +220,43 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
 		 : (hardware ? bp_hardware_breakpoint : bp_breakpoint));
   ops = tracepoint ? &tracepoint_breakpoint_ops : &bkpt_breakpoint_ops;
 
-  location = string_to_event_location (&address, current_language);
-  make_cleanup (delete_event_location, location);
+  if (is_explicit)
+    {
+      location = new_event_location (EVENT_LOCATION_EXPLICIT);
+      make_cleanup (delete_event_location, location);
+
+      if (explicit.source_filename != NULL)
+	{
+	  EVENT_LOCATION_EXPLICIT (location)->source_filename
+	    = explicit.source_filename;
+
+	  /* 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."));
+	}
+
+      if (explicit.function_name != NULL)
+	EVENT_LOCATION_EXPLICIT (location)->function_name
+	  = explicit.function_name;
+
+      if (explicit.label_name != NULL)
+	EVENT_LOCATION_EXPLICIT (location)->label_name
+	  = explicit.label_name;
+
+      if (explicit.line_offset.sign != LINE_OFFSET_UNKNOWN)
+	EVENT_LOCATION_EXPLICIT (location)->line_offset
+	  = explicit.line_offset;
+    }
+  else
+    {
+      location = string_to_event_location (&address, current_language);
+      make_cleanup (delete_event_location, location);
+    }
+
   create_breakpoint (get_current_arch (), location, condition, thread,
 		     NULL,
 		     0 /* condition and thread are valid.  */,
diff --git a/gdb/testsuite/gdb.base/save-bp.exp b/gdb/testsuite/gdb.base/save-bp.exp
index fa3c5dd..280170b 100644
--- a/gdb/testsuite/gdb.base/save-bp.exp
+++ b/gdb/testsuite/gdb.base/save-bp.exp
@@ -46,6 +46,8 @@ 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"
+
 # Now, save the breakpoints into a file...
 remote_file host delete "bps"
 gdb_test "save breakpoint bps"
@@ -65,5 +67,164 @@ gdb_test "source bps"
 
 # Now, verify that all breakpoints have been created correctly...
 set bp_row_start "\[0-9\]+ +breakpoint +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"
+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\]+"
+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 breakpoint bps"
+set fd [open "bps" "r"]
+set line [gets $fd]
+if {[string equal $line "break *break_me"]} {
+    pass "save address breakpoint"
+} else {
+    fail "save address breakpoint"
+    send_log "got \"$line\"\n"
+}
+close $fd
+remote_file host delete "bps"
+
+# 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 pending-bps" "Saved to file 'pending-bps'." \
+    "save pending breakpoints"
+
+# Now read in the file, and verify the contents line-by-line.
+set fd [open "pending-bps" "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
+
+# 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 bps" "Saved to file 'bps'." \
+    "save resolved breakpoints"
+
+unset pending
+set fd [open "bps" "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
+
+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
+remote_file host delete "bps"
+remote_file host delete "pending-bps"
+
+# 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 bps" "Saved to file 'bps'." \
+    "save empty linespec breakpoint"
+gdb_test "shell cat bps" "break \\*0x.*" \
+    "empty linespec saved properly"
+remote_file host delete "bps"
+delete_breakpoints
+
+unset -nocomplain bp_list pending fd spec elem line test
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..d59f4ee
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.c
@@ -0,0 +1,54 @@
+/* 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/>.  */
+
+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 j;
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
new file mode 100644
index 0000000..53a23d0
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,197 @@
+# 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
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile $srcfile \
+	 {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)
+
+# 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.
+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 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 $objdir/$subdir/$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 $objdir/$subdir/$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
+
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 9cf0126..3b01451 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -259,6 +259,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
 
@@ -272,5 +361,7 @@ test_breakpoint_commands
 
 test_abreak_creation
 
+test_explicit_breakpoints
+
 mi_gdb_exit
 return 0
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 50b926f..9cb5cf5 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 } {

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