public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
@ 2015-05-07 18:05 ` Keith Seitz
  2015-05-17 20:54   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Keith Seitz
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:05 UTC (permalink / raw)
  To: gdb-patches

This patch introduces the new breakpoint/"linespec" API based on
a new struct event_location.  This API currently only supports
traditional linespecs, maintaining the status quo of the code base.
Future patches will add additional functionality for other location
types such as address locations.

gdb/ChangeLog:

	* Makefile.in (SFILES): Add location.c.
	(HFILES_NO_SRCDIR): Add location.h.
	(COMMON_OBS): Add location.o.
	* linespec.c (linespec_lex_to_end): New function.
	* linespec.c (linespec_lex_to_end): Declare.
	* location.c: New file.
	* location.h: New file.
---
 gdb/Makefile.in |    6 +
 gdb/linespec.c  |   55 +++++++++++++
 gdb/linespec.h  |    5 +
 gdb/location.c  |  234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/location.h  |  113 +++++++++++++++++++++++++++
 5 files changed, 410 insertions(+), 3 deletions(-)
 create mode 100644 gdb/location.c
 create mode 100644 gdb/location.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 95104ef..0a51564 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -851,7 +851,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	inline-frame.c \
 	interps.c \
 	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c jv-varobj.c \
-	language.c linespec.c minidebug.c \
+	language.c linespec.c location.c minidebug.c \
 	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
 	macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
 	mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
@@ -937,7 +937,7 @@ mi/mi-out.h mi/mi-main.h mi/mi-common.h mi/mi-cmds.h linux-nat.h \
 complaints.h gdb_proc_service.h gdb_regex.h xtensa-tdep.h inf-loop.h \
 common/gdb_wait.h common/gdb_assert.h solib.h ppc-tdep.h cp-support.h glibc-tdep.h \
 interps.h auxv.h gdbcmd.h tramp-frame.h mipsnbsd-tdep.h	\
-amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \
+amd64-linux-tdep.h linespec.h location.h i387-tdep.h mn10300-tdep.h \
 sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h \
 coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
 m68k-tdep.h spu-tdep.h jv-lang.h environ.h amd64-tdep.h \
@@ -1021,7 +1021,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
 	block.o symtab.o psymtab.o symfile.o symfile-debug.o symmisc.o \
 	linespec.o dictionary.o \
-	infcall.o \
+	location.o infcall.o \
 	infcmd.o infrun.o \
 	expprint.o environ.o stack.o thread.o \
 	exceptions.o \
diff --git a/gdb/linespec.c b/gdb/linespec.c
index d2089b5..a480be1 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -2435,6 +2435,61 @@ linespec_parser_delete (void *arg)
   linespec_state_destructor (PARSER_STATE (parser));
 }
 
+/* See description in linespec.h.  */
+
+void
+linespec_lex_to_end (char **stringp)
+{
+  linespec_parser parser;
+  struct cleanup *cleanup;
+  linespec_token token;
+  volatile struct gdb_exception e;
+  const char *orig;
+
+  if (stringp == NULL || *stringp == NULL)
+    return;
+
+  linespec_parser_new (&parser, 0, current_language, NULL, 0, NULL);
+  cleanup = make_cleanup (linespec_parser_delete, &parser);
+  parser.lexer.saved_arg = *stringp;
+  PARSER_STREAM (&parser) = orig = *stringp;
+
+  TRY
+    {
+      do
+	{
+	  /* Stop before any comma tokens;  we need it to keep it
+	     as the next token in the string.  */
+	  token = linespec_lexer_peek_token (&parser);
+	  if (token.type == LSTOKEN_COMMA)
+	    break;
+
+	  /* For addresses advance the parser stream past
+	     any parsed input and stop lexing.  */
+	  if (token.type == LSTOKEN_STRING
+	      && *LS_TOKEN_STOKEN (token).ptr == '*')
+	    {
+	      const char *arg;
+
+	      arg = *stringp;
+	      (void) linespec_expression_to_pc (&arg);
+	      PARSER_STREAM (&parser) = arg;
+	      break;
+	    }
+
+	  token = linespec_lexer_consume_token (&parser);
+	}
+      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
+    }
+  CATCH (e, RETURN_MASK_ERROR)
+    {
+    }
+  END_CATCH
+
+  *stringp += PARSER_STREAM (&parser) - orig;
+  do_cleanups (cleanup);
+}
+
 /* See linespec.h.  */
 
 void
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 7e66024..77ec46d 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -156,4 +156,9 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
    the keyword.  If not, return NULL.  */
 
 extern const char *linespec_lexer_lex_keyword (const char *p);
+
+/* Find the end of the (first) linespec pointed to by *STRINGP.
+   STRINGP will be advanced to this point.  */
+
+extern void linespec_lex_to_end (char **stringp);
 #endif /* defined (LINESPEC_H) */
diff --git a/gdb/location.c b/gdb/location.c
new file mode 100644
index 0000000..39e09c1
--- /dev/null
+++ b/gdb/location.c
@@ -0,0 +1,234 @@
+/* Data structures and API for event locations in GDB.
+   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "gdb_assert.h"
+#include "location.h"
+#include "symtab.h"
+#include "language.h"
+#include "linespec.h"
+#include "cli/cli-utils.h"
+#include "probe.h"
+
+#include <ctype.h>
+#include <string.h>
+
+/* An event location used to set a stop event in the inferior.
+   This structure is an amalgam of the various ways
+   to specify where a stop event should be set.  */
+
+struct event_location
+{
+  /* The type of this breakpoint specification.  */
+  enum event_location_type type;
+#define EL_TYPE(PTR) (PTR)->type
+
+  union
+  {
+    /* A generic "this is a string specification" for a location.
+       This representation is used by both "normal" linespecs and
+       probes.  */
+    char *addr_string;
+#define EL_LINESPEC(PTR) ((PTR)->u.addr_string)
+  } u;
+
+  /* Cached string representation of this location.  This is used, e.g., to
+     save stop event locations to file.  Malloc'd.  */
+  char *as_string;
+#define EL_STRING(PTR) ((PTR)->as_string)
+};
+
+/* See description in location.h.  */
+
+enum event_location_type
+event_location_type (const struct event_location *location)
+{
+  return EL_TYPE (location);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
+new_linespec_location (char **linespec)
+{
+  struct event_location *location;
+
+  location = XCNEW (struct event_location);
+  EL_TYPE (location) = LINESPEC_LOCATION;
+  if (*linespec != NULL)
+    {
+      char *p;
+      char *orig = *linespec;
+
+      linespec_lex_to_end (linespec);
+      p = remove_trailing_whitespace (orig, *linespec);
+      if ((p - orig) > 0)
+	EL_LINESPEC (location) = savestring (orig, p - orig);
+    }
+  return location;
+}
+
+/* See description in location.h.  */
+
+const char *
+get_linespec_location (const struct event_location *location)
+{
+  gdb_assert (EL_TYPE (location) == LINESPEC_LOCATION);
+  return EL_LINESPEC (location);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
+copy_event_location (const struct event_location *src)
+{
+  struct event_location *dst;
+
+  dst = XCNEW (struct event_location);
+  EL_TYPE (dst) = EL_TYPE (src);
+  if (EL_STRING (src) != NULL)
+    EL_STRING (dst) = xstrdup (EL_STRING (src));
+
+  switch (EL_TYPE (src))
+    {
+    case LINESPEC_LOCATION:
+      if (EL_LINESPEC (src) != NULL)
+	EL_LINESPEC (dst) = xstrdup (EL_LINESPEC (src));
+      break;
+
+    default:
+      gdb_assert_not_reached ("unknown event location type");
+    }
+
+  return dst;
+}
+
+/* A cleanup function for struct event_location.  */
+
+static void
+delete_event_location_cleanup (void *data)
+{
+  struct event_location *location = (struct event_location *) data;
+
+  delete_event_location (location);
+}
+
+/* See description in location.h.  */
+
+struct cleanup *
+make_cleanup_delete_event_location (struct event_location *location)
+{
+  return make_cleanup (delete_event_location_cleanup, location);
+}
+
+/* See description in location.h.  */
+
+void
+delete_event_location (struct event_location *location)
+{
+  if (location != NULL)
+    {
+      xfree (EL_STRING (location));
+
+      switch (EL_TYPE (location))
+	{
+	case LINESPEC_LOCATION:
+	  xfree (EL_LINESPEC (location));
+	  break;
+
+	default:
+	  gdb_assert_not_reached ("unknown event location type");
+	}
+
+      xfree (location);
+    }
+}
+
+/* See description in location.h.  */
+
+char *
+event_location_to_string_const (const struct event_location *location)
+{
+  char *result = NULL;
+
+  if (EL_STRING (location) != NULL)
+    return xstrdup (EL_STRING (location));
+
+  switch (EL_TYPE (location))
+    {
+    case LINESPEC_LOCATION:
+      if (EL_LINESPEC (location) != NULL)
+	result = xstrdup (EL_LINESPEC (location));
+      break;
+
+    default:
+      gdb_assert_not_reached ("unknown event location type");
+    }
+
+  return result;
+}
+
+/* See description in location.h.  */
+
+const char *
+event_location_to_string (struct event_location *location)
+{
+  /* Cache a copy of the string representation.  */
+  if (EL_STRING (location) == NULL)
+    EL_STRING (location) = event_location_to_string_const (location);
+
+  return EL_STRING (location);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
+string_to_event_location (char **stringp,
+			  const struct language_defn *language)
+{
+  struct event_location *location;
+
+  location = new_linespec_location (stringp);
+  return location;
+}
+
+/* See description in location.h.  */
+
+int
+event_location_empty_p (const struct event_location *location)
+{
+  switch (EL_TYPE (location))
+    {
+    case LINESPEC_LOCATION:
+      /* Linespecs are never "empty."  (NULL is a valid linespec)  */
+      return 0;
+
+    default:
+      gdb_assert_not_reached ("unknown event location type");
+    }
+}
+
+/* See description in location.h.  */
+
+void
+set_event_location_string (struct event_location *location,
+			   const char *string)
+{
+  xfree (EL_STRING (location));
+  EL_STRING (location) = string == NULL ?  NULL : xstrdup (string);
+}
diff --git a/gdb/location.h b/gdb/location.h
new file mode 100644
index 0000000..992f21e
--- /dev/null
+++ b/gdb/location.h
@@ -0,0 +1,113 @@
+/* Data structures and API for event locations in GDB.
+   Copyright (C) 2013-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef LOCATIONS_H
+#define LOCATIONS_H 1
+
+struct language_defn;
+struct event_location;
+
+/* An enumeration of the various ways to specify a stop event
+   location (used with create_breakpoint).  */
+
+enum event_location_type
+{
+  /* A traditional linespec.  */
+  LINESPEC_LOCATION
+};
+
+/* Return the type of the given event location.  */
+
+extern enum event_location_type
+  event_location_type (const struct event_location *);
+
+/* Return a string representation of the LOCATION.
+   This function may return NULL for unspecified linespecs,
+   e.g, LOCATION_LINESPEC and addr_string is NULL.
+
+   The result is cached in LOCATION.  */
+
+extern const char *
+  event_location_to_string (struct event_location *location);
+
+/* A const version of event_location_to_string that will not cache
+   the resulting string representation.  The result is malloc'd
+   and must be freed by the caller.  */
+
+extern char *
+  event_location_to_string_const (const struct event_location *location);
+
+/* Create a new linespec location.  The return result is malloc'd
+   and should be freed with delete_event_location.  */
+
+extern struct event_location *
+  new_linespec_location (char **linespec);
+
+/* Return the linespec location (a string) of the given event_location
+   (which must be of type LINESPEC_LOCATION).  */
+
+extern const char *
+  get_linespec_location (const struct event_location *location);
+
+/* Free an event location and any associated data.  */
+
+extern void delete_event_location (struct event_location *location);
+
+/* Make a cleanup to free LOCATION.  */
+
+extern struct cleanup *
+  make_cleanup_delete_event_location (struct event_location *location);
+
+/* Return a copy of the given SRC location.  */
+
+extern struct event_location *
+  copy_event_location (const struct event_location *src);
+
+/* Allocate and "copy" the opaque struct event_location.  This is used
+   when decoding locations which must parse their inputs.  The return result
+   should be freed.  */
+
+extern struct event_location *
+  copy_event_location_tmp (const struct event_location *src);
+
+/* 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.
+
+   The return result must be freed with delete_event_location.  */
+
+extern struct event_location *
+  string_to_event_location (char **argp,
+			    const struct language_defn *langauge);
+
+/* A convenience function for testing for unset locations.  */
+
+extern int event_location_empty_p (const struct event_location *location);
+
+/* Set the location's string representation.  If STRING is NULL, clear
+   the string representation.  */
+
+extern void
+  set_event_location_string (struct event_location *location,
+			     const char *string);
+#endif /* LOCATIONS_H */

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 0/9] Locations API
@ 2015-05-07 18:05 Keith Seitz
  2015-05-07 18:05 ` [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
                   ` (8 more replies)
  0 siblings, 9 replies; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:05 UTC (permalink / raw)
  To: gdb-patches

This is the next revision of the locations/explicit locations mega-API
change on which I've been working. Most of the changes in this
revision are fairly trivial.

As a reminder, this series proposes to change the API for create_breakpoint
and related functions to:

void
my_command (char *arg, int from_tty)
{
  struct event_location *location;
  struct cleanup *cleanup;

  location = string_to_event_location (&arg, current_language);
  cleanup = make_cleanup_delete_event_location (location);
  if (*arg)
    error ("junk at end of command");
  /* do whatever with location, e.g., create_breakpoint (location, ...);  */
  do_cleanups (cleanup);
}

As with the previous revision, explicit-ui-cli tests will cause several
internal-errors because of gdb/17960 (internal-error when completing
"source.c:func").

This is easily fixed after that patch has been committed. This series
sent as-is does /not/ depend on those patches being applied.

---

Keith Seitz (9):
      Explicit locations: rename "address string"/"addr_string" to "location"
      Explicit locations: introduce new struct event_location-based API
      Explicit locations: use new location API
      Explicit locations: introduce address locations
      Explicit locations: introduce probe locations
      Explicit locations: introduce explicit locations
      Explicit locations: add UI features for CLI
      Explicit locations: MI support for explicit locations
      Explicit locations: documentation updates


 gdb/Makefile.in                           |    6 
 gdb/NEWS                                  |    4 
 gdb/ax-gdb.c                              |    8 
 gdb/break-catch-throw.c                   |   23 +
 gdb/breakpoint.c                          |  747 +++++++++++++++++------------
 gdb/breakpoint.h                          |   51 +-
 gdb/cli/cli-cmds.c                        |   47 ++
 gdb/completer.c                           |  219 ++++++++-
 gdb/doc/gdb.texinfo                       |  234 ++++++---
 gdb/elfread.c                             |    4 
 gdb/guile/scm-breakpoint.c                |   23 +
 gdb/linespec.c                            |  589 ++++++++++++++---------
 gdb/linespec.h                            |   42 +-
 gdb/location.c                            |  734 ++++++++++++++++++++++++++++
 gdb/location.h                            |  238 +++++++++
 gdb/mi/mi-cmd-break.c                     |   76 +++
 gdb/probe.c                               |   20 +
 gdb/probe.h                               |    6 
 gdb/python/py-breakpoint.c                |   12 
 gdb/python/py-finishbreakpoint.c          |   16 -
 gdb/python/python.c                       |   26 +
 gdb/remote.c                              |   10 
 gdb/spu-tdep.c                            |   11 
 gdb/testsuite/gdb.base/help.exp           |    2 
 gdb/testsuite/gdb.linespec/3explicit.c    |   28 +
 gdb/testsuite/gdb.linespec/cpexplicit.cc  |   63 ++
 gdb/testsuite/gdb.linespec/cpexplicit.exp |  112 ++++
 gdb/testsuite/gdb.linespec/explicit.c     |   56 ++
 gdb/testsuite/gdb.linespec/explicit.exp   |  393 +++++++++++++++
 gdb/testsuite/gdb.linespec/explicit2.c    |   24 +
 gdb/testsuite/gdb.linespec/ls-errs.exp    |   45 +-
 gdb/testsuite/gdb.mi/mi-break.exp         |   82 +++
 gdb/testsuite/gdb.mi/mi-dprintf.exp       |   12 
 gdb/testsuite/lib/mi-support.exp          |   16 +
 gdb/tracepoint.c                          |   16 +
 gdb/tracepoint.h                          |    2 
 36 files changed, 3230 insertions(+), 767 deletions(-)
 create mode 100644 gdb/location.c
 create mode 100644 gdb/location.h
 create mode 100644 gdb/testsuite/gdb.linespec/3explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit2.c

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 3/9] Explicit locations: use new location API
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (6 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  5:21   ` Doug Evans
  2015-05-07 18:13 ` [PATCH v4 9/9] Explicit locations: documentation updates Keith Seitz
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch converts the code base to use the new struct event_location
API being introduced. This patch preserves the current functionality and
adds no new features.

The "big picture" API usage introduced by this patch may be illustrated
with a simple exmaple. Where previously developers would write:

void
my_command (char *arg, int from_tty)
{
   create_breakpoint (..., arg, ...);
   ...
}

one now uses:

void
my_command (char *arg, int from_tty)
{
   struct event_locaiton *location;
   struct cleanup *back_to;

   location = string_to_event_locaiton (&arg, ...);
   back_to = make_cleanup_delete_event_location (location);
   create_breakpoint (..., location, ...);
   do_cleanups (back_to);
}

Linespec-decoding functions (now called location-decoding) such as
decode_line_full no longer skip argument pointers over processed input.
That functionality has been moved into string_to_event_location as
demonstrated above.

gdb/ChangeLog

	* ax-gdb.c: Include location.h.
	(agent_command_1) Use linespec location instead of address
	string.
	* break-catch-throw.c: Include location.h.
	(re_set_exception_catchpoint): Use linespec locations instead
	of address strings.
	* breakpoint.c: Include location.h.
	(create_overlay_event_breakpoint): Use linespec location
	instead of address string.
	(create_longjmp_master_breakpoint): Likewise.
	(create_std_terminate_master_breakpoint): Likewise.
	(create_exception_master_breakpoint): Likewise.
	(update_breakpoints_after_exec): Likewise.
	(print_breakpoint_location): Use locations and
	event_location_to_string.
	(print_one_breakpoint_location): Likewise.
	(init_raw_breakpoint_without_location): Initialize
	b->location.
	(create_thread_event_breakpoint): Use linespec location instead of
	address string.
	(init_breakpoint_sal): Likewise.
	Only save extra_string if it is non-NULL and not the empty string.
	Use event_location_to_string instead of `addr_string'.
	Constify `p' and `endp'.
	Use skip_spaces_const/skip_space_const instead of non-const versions.
	Copy the location into the breakpoint.
	If LOCATION is NULL, save the breakpoint address as a linespec location
	instead of an address string.
	(create_breakpoint_sal): Change `addr_string' parameter to a struct
	event_location. All uses updated.
	(create_breakpoints_sal): Likewise for local variable `addr_string'.
	(parse_breakpoint_sals): Use locations instead of address strings.
	Remove check for empty linespec with conditional.
	Refactor.
	(decode_static_tracepoint_spec): Make argument const and update
	function.
	(create_breakpoint): Change `arg' to a struct event_location and
	rename.
	Remove `copy_arg' and `addr_start'.
	If EXTRA_STRING is empty, set it to NULL.
	Don't populate `canonical' for pending breakpoints.
	Pass `extra_string' to find_condition_and_thread.
	Clear `extra_string' if `rest' was NULL.
	Do not error with "garbage after location" if setting a dprintf
	breakpoint.
	Copy the location into the breakpoint instead of an address string.
	For pending breakpoints, append `extra_string' to the location's
	string representation and make a private copy of `extra_string' for
	the breakpoint.
	(break_command_1): Use string_to_event_location and pass this to
	create_breakpoint instead of an address string.
	Check against `arg_cp' for a probe linespec.
	(dprintf_command): Use string_to_event_location and pass this to
	create_breakpoint instead of an address string.
	(print_recreate_ranged_breakpoint): Use event_location_to_string
	instead of address strings.
	(break_range_command): Use locations instead of address strings.
	(until_break_command): Likewise.
	(init_ada_exception_breakpoint): Likewise.
	(say_where): Likewise.
	(base_breakpoint_dtor): Delete `location' and `location_range_end' of
	the breakpoint.
	(base_breakpoint_create_sals_from_location): Use struct event_location
	instead of address string.
	Remove `addr_start' and `copy_arg' parameters.
	(base_breakpoint_decode_location): Use struct event_location instead of
	address string.
	(bkpt_re_set): Use locations instead of address strings.
	Use event_location_empty_p to check for unset location.
	(bkpt_print_recreate): Use event_location_to_string instead of
	an address string.
	(bkpt_create_sals_from_location): Use struct event_location instead of
	address string.
	(bkpt_decode_location): Likewise.
	(bkpt_probe_create_sals_from_location): Likewise.
	(bkpt_probe_decode_location): Use struct event_location instead of
	address string.
	(tracepoint_print_recreate): Use event_location_to_string to
	recreate the tracepoint.
	(tracepoint_create_sals_from_location): Use struct event_location
	instead of address string.
	(tracepoint_decode_location): Likewise.
	(tracepoint_probe_create_sals_from_location): Likewise.
	(tracepoint_probe_decode_location): Likewise.
	(dprintf_print_recreate): Use event_location_to_string to recreate
	the dprintf.
	(strace_marker_create_sals_from_location): Use struct event_location
	instead of address string.
	(strace_marker_create_breakpoints_sal): Likewise.
	(strace_marker_decode_location): Likewise.
	(update_static_tracepoint): Likewise.
	(location_to_sals): Likewise.
	Pass `extra_string' to find_condition_and_thread.
	For newly resolved pending breakpoint locations, clear the location's
	string representation.
	(breakpoint_re_set_default): Use locations instead of address
	strings.
	(create_sals_from_location_default): Likewise.
	(decode_location_default): Use locations instead of address strings.
	(trace_command): Use locations instead of address strings.
	(ftrace_command): Likewise.
	(strace_command): Likewise.
	(create_tracepoint_from_upload): Likewise.
	* breakpoint.h (struct breakpoint_ops) <create_sals_from_location>:
	Use struct event_location instead of address string.
	Update all uses.
	<decode_location>: Likewise.
	(struct breakpoint) <addr_string>: Change to struct event_location
	and rename `location'.
	<addr_string_range_end>: Change to struct event_location and rename
	`location_range_end'.
	(create_breakpoint): Use struct event_location instead of address
	string.
	* cli/cli-cmds.c: Include location.h.
	(edit_command): Use locations instead of address strings.
	(list_command): Likewise.
	* elfread.c: Include location.h.
	(elf_gnu_ifunc_resolver_return_stop): Use event_location_to_string.
	* guile/scm-breakpoint.c: Include location.h.
	(bpscm_print_breakpoint_smob): Use event_location_to_string.
	(gdbscm_register_breakpoint): Use locations instead of address
	strings.
	* linespec.c: Include location.h.
	(struct ls_parser) <stream>: Change to const char *.
	(PARSER_STREAM): Update.
	(lionespec_lexer_lex_keyword): According to find_condition_and_thread,
	keywords must be followed by whitespace.
	(canonicalize_linespec): Save a linespec location into `canonical'.
	Save a canonical linespec into `canonical'.
	(parse_linespec): Change `argptr' to const char * and rename `arg'.
	All uses updated.
	Update function description.
	(linespec_parser_new): Initialize `parser'.
	Update initialization of  parsing stream.
	(event_location_to_sals): New function.
	(decode_line_full): Change `argptr' to a struct event_location and
	rename it `location'.
	Use locations instead of address strings.
	Call event_location_to_sals instead of parse_linespec.
	(decode_line_1): Likewise.
	(decode_line_with_current_source): Use locations instead of
	address strings.
	(decode_line_with_last_displayed): Likewise.
	(decode_objc): Likewise.
	Change `argptr' to const char * and rename `arg'.
	(destroy_linespec_result): Delete the linespec result's location
	instead of freeing the address string.
	* linespec.h (struct linespec_result) <addr_string>: Change to
	struct event_location and rename to ...
	<location>: ... this.
	(decode_line_1): Change `argptr' to struct event_location.
	All callers updated.
	(decode_line_full): Likewise.
	* mi/mi-cmd-break.c: Include language.h, location.h, and linespec.h.
	(mi_cmd_break_insert_1): Use locations instead of address strings.
	Throw an error if there was "garbage" at the end of the specified
	linespec.
	* probe.c: Include location.h.
	(parse_probes): Change `argptr' to struct event_location.
	Use event locations instead of address strings.
	* probe.h (parse_probes): Change `argptr' to struct event_location.
	* python/py-breakpoint.c: Include location.h.
	(bppy_get_location): Constify local variable `str'.
	Use event_location_to_string.
	(bppy_init): Use locations instead of address strings.
	* python/py-finishbreakpoint.c: Include location.h.
	(bpfinishpy_init): Remove local variable `addr_str'.
	Use locations instead of address strings.
	* python/python.c: Include location.h.
	(gdbpy_decode_line): Use locations instead of address strings.
	* remote.c: Include location.h.
	(remote_download_tracepoint): Use locations instead of address
	strings.
	* spu-tdep.c: Include location.h.
	(spu_catch_start): Remove local variable `buf'.
	Use locations instead of address strings.
	* tracepoint.c: Include location.h.
	(scope_info): Use locations instead of address strings.
	(encode_source_string): Constify parameter `src'.
	* tracepoint.h (encode_source_string): Likewise.
---
 gdb/ax-gdb.c                     |    8 
 gdb/break-catch-throw.c          |   13 +
 gdb/breakpoint.c                 |  656 +++++++++++++++++++++++---------------
 gdb/breakpoint.h                 |   43 ++
 gdb/cli/cli-cmds.c               |   47 ++-
 gdb/elfread.c                    |    4 
 gdb/guile/scm-breakpoint.c       |   23 +
 gdb/linespec.c                   |  142 ++++++--
 gdb/linespec.h                   |   12 -
 gdb/mi/mi-cmd-break.c            |   12 +
 gdb/probe.c                      |   19 +
 gdb/probe.h                      |    6 
 gdb/python/py-breakpoint.c       |   12 -
 gdb/python/py-finishbreakpoint.c |   14 +
 gdb/python/python.c              |   26 +-
 gdb/remote.c                     |   10 -
 gdb/spu-tdep.c                   |   12 +
 gdb/tracepoint.c                 |   16 +
 gdb/tracepoint.h                 |    2 
 19 files changed, 690 insertions(+), 387 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 7a9d1e7..2fd5a1a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -40,6 +40,7 @@
 #include "arch-utils.h"
 #include "cli/cli-utils.h"
 #include "linespec.h"
+#include "location.h"
 #include "objfiles.h"
 
 #include "valprint.h"
@@ -2642,13 +2643,16 @@ agent_command_1 (char *exp, int eval)
       int ix;
       struct linespec_sals *iter;
       struct cleanup *old_chain;
+      struct event_location *location;
 
       exp = skip_spaces (exp);
       init_linespec_result (&canonical);
-      decode_line_full (&exp, DECODE_LINE_FUNFIRSTLINE,
+      location = new_linespec_location (&exp);
+      old_chain = make_cleanup_delete_event_location (location);
+      decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
 			(struct symtab *) NULL, 0, &canonical,
 			NULL, NULL);
-      old_chain = make_cleanup_destroy_linespec_result (&canonical);
+      make_cleanup_destroy_linespec_result (&canonical);
       exp = skip_spaces (exp);
       if (exp[0] == ',')
         {
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 927176f..9449aa5 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -35,6 +35,7 @@
 #include "cp-abi.h"
 #include "gdb_regex.h"
 #include "cp-support.h"
+#include "location.h"
 
 /* Enums for exception-handling support.  */
 enum exception_event_kind
@@ -210,25 +211,31 @@ re_set_exception_catchpoint (struct breakpoint *self)
   struct symtabs_and_lines sals_end = {0};
   struct cleanup *cleanup;
   enum exception_event_kind kind = classify_exception_breakpoint (self);
+  struct event_location *location;
 
   /* We first try to use the probe interface.  */
   TRY
     {
       char *spec = ASTRDUP (exception_functions[kind].probe);
 
-      sals = parse_probes (&spec, NULL);
+      location = new_linespec_location (&spec);
+      cleanup = make_cleanup_delete_event_location (location);
+      sals = parse_probes (location, NULL);
+      do_cleanups (cleanup);
     }
 
   CATCH (e, RETURN_MASK_ERROR)
     {
-
       /* Using the probe interface failed.  Let's fallback to the normal
 	 catchpoint mode.  */
       TRY
 	{
 	  char *spec = ASTRDUP (exception_functions[kind].function);
 
-	  self->ops->decode_location (self, &spec, &sals);
+	  location = new_linespec_location (&spec);
+	  cleanup = make_cleanup_delete_event_location (location);
+	  self->ops->decode_location (self, location, &sals);
+	  do_cleanups (cleanup);
 	}
       CATCH (ex, RETURN_MASK_ERROR)
 	{
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 31b1f82..549bfd0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -67,6 +67,7 @@
 #include "dummy-frame.h"
 #include "interps.h"
 #include "format.h"
+#include "location.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -108,10 +109,10 @@ static int breakpoint_re_set_one (void *);
 
 static void breakpoint_re_set_default (struct breakpoint *);
 
-static void create_sals_from_location_default (char **,
-					       struct linespec_result *,
-					       enum bptype, char *,
-					       char **);
+static void
+  create_sals_from_location_default (const struct event_location *location,
+				     struct linespec_result *canonical,
+				     enum bptype type_wanted);
 
 static void create_breakpoints_sal_default (struct gdbarch *,
 					    struct linespec_result *,
@@ -121,8 +122,9 @@ static void create_breakpoints_sal_default (struct gdbarch *,
 					    const struct breakpoint_ops *,
 					    int, int, int, unsigned);
 
-static void decode_location_default (struct breakpoint *, char **,
-				     struct symtabs_and_lines *);
+static void decode_location_default (struct breakpoint *b,
+				     const struct event_location *location,
+				     struct symtabs_and_lines *sals);
 
 static void clear_command (char *, int);
 
@@ -3412,6 +3414,7 @@ create_overlay_event_breakpoint (void)
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      char *p;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3436,7 +3439,8 @@ create_overlay_event_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_overlay_event,
 				      &internal_breakpoint_ops);
-      b->addr_string = xstrdup (func_name);
+      p = ASTRDUP (func_name);
+      b->location = new_linespec_location (&p);
 
       if (overlay_debugging == ovly_auto)
         {
@@ -3503,6 +3507,7 @@ create_longjmp_master_breakpoint (void)
 	  int i;
 	  struct probe *probe;
 	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+	  char *p;
 
 	  for (i = 0;
 	       VEC_iterate (probe_p,
@@ -3517,7 +3522,8 @@ create_longjmp_master_breakpoint (void)
 								 objfile),
 					      bp_longjmp_master,
 					      &internal_breakpoint_ops);
-	      b->addr_string = xstrdup ("-probe-stap libc:longjmp");
+	      p = ASTRDUP ("-probe-stap libc:longjmp");
+	      b->location = new_linespec_location (&p);
 	      b->enable_state = bp_disabled;
 	    }
 
@@ -3532,6 +3538,7 @@ create_longjmp_master_breakpoint (void)
 	  struct breakpoint *b;
 	  const char *func_name;
 	  CORE_ADDR addr;
+	  char *p;
 
 	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
 	    continue;
@@ -3554,7 +3561,8 @@ create_longjmp_master_breakpoint (void)
 	  addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
 	  b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
 					  &internal_breakpoint_ops);
-	  b->addr_string = xstrdup (func_name);
+	  p = ASTRDUP (func_name);
+	  b->location = new_linespec_location (&p);
 	  b->enable_state = bp_disabled;
 	}
     }
@@ -3585,6 +3593,7 @@ create_std_terminate_master_breakpoint (void)
     {
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
+      char *p;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3610,7 +3619,8 @@ create_std_terminate_master_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_std_terminate_master,
 				      &internal_breakpoint_ops);
-      b->addr_string = xstrdup (func_name);
+      p = ASTRDUP (func_name);
+      b->location = new_linespec_location (&p);
       b->enable_state = bp_disabled;
     }
   }
@@ -3634,6 +3644,7 @@ create_exception_master_breakpoint (void)
       struct gdbarch *gdbarch;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      char *p;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3674,13 +3685,15 @@ create_exception_master_breakpoint (void)
 	       ++i)
 	    {
 	      struct breakpoint *b;
+	      char *p;
 
 	      b = create_internal_breakpoint (gdbarch,
 					      get_probe_address (probe,
 								 objfile),
 					      bp_exception_master,
 					      &internal_breakpoint_ops);
-	      b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
+	      p = ASTRDUP ("-probe-stap libgcc:unwind");
+	      b->location = new_linespec_location (&p);
 	      b->enable_state = bp_disabled;
 	    }
 
@@ -3713,7 +3726,8 @@ create_exception_master_breakpoint (void)
 						 &current_target);
       b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 				      &internal_breakpoint_ops);
-      b->addr_string = xstrdup (func_name);
+      p = ASTRDUP (func_name);
+      b->location = new_linespec_location (&p);
       b->enable_state = bp_disabled;
     }
 
@@ -3834,7 +3848,7 @@ update_breakpoints_after_exec (void)
     /* Without a symbolic address, we have little hope of the
        pre-exec() address meaning the same thing in the post-exec()
        a.out.  */
-    if (b->addr_string == NULL)
+    if (event_location_empty_p (b->location))
       {
 	delete_breakpoint (b);
 	continue;
@@ -6021,7 +6035,8 @@ print_breakpoint_location (struct breakpoint *b,
     set_current_program_space (loc->pspace);
 
   if (b->display_canonical)
-    ui_out_field_string (uiout, "what", b->addr_string);
+    ui_out_field_string (uiout, "what",
+			 event_location_to_string (b->location));
   else if (loc && loc->symtab)
     {
       struct symbol *sym 
@@ -6057,7 +6072,8 @@ print_breakpoint_location (struct breakpoint *b,
       do_cleanups (stb_chain);
     }
   else
-    ui_out_field_string (uiout, "pending", b->addr_string);
+    ui_out_field_string (uiout, "pending",
+			 event_location_to_string (b->location));
 
   if (loc && is_breakpoint (b)
       && breakpoint_condition_evaluation_mode () == condition_evaluation_target
@@ -6526,8 +6542,10 @@ print_one_breakpoint_location (struct breakpoint *b,
 
 	  ui_out_field_string (uiout, "original-location", w->exp_string);
 	}
-      else if (b->addr_string)
-	ui_out_field_string (uiout, "original-location", b->addr_string);
+      else if (b->location != NULL
+	       && event_location_to_string (b->location) != NULL)
+	ui_out_field_string (uiout, "original-location",
+			     event_location_to_string (b->location));
     }
 }
 
@@ -7297,6 +7315,7 @@ init_raw_breakpoint_without_location (struct breakpoint *b,
   b->condition_not_parsed = 0;
   b->py_bp_object = NULL;
   b->related_breakpoint = b;
+  b->location = NULL;
 }
 
 /* Helper to set_raw_breakpoint below.  Creates a breakpoint
@@ -7637,15 +7656,19 @@ delete_std_terminate_breakpoint (void)
 struct breakpoint *
 create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
+  char *tmp;
   struct breakpoint *b;
+  struct cleanup *cleanup;
 
   b = create_internal_breakpoint (gdbarch, address, bp_thread_event,
 				  &internal_breakpoint_ops);
 
   b->enable_state = bp_enabled;
-  /* addr_string has to be used or breakpoint_re_set will delete me.  */
-  b->addr_string
-    = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+  /* location has to be used or breakpoint_re_set will delete me.  */
+  tmp = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+  cleanup = make_cleanup (xfree, tmp);
+  b->location = new_linespec_location (&tmp);
+  do_cleanups (cleanup);
 
   update_global_location_list_nothrow (UGLL_MAY_INSERT);
 
@@ -9083,13 +9106,14 @@ update_dprintf_commands (char *args, int from_tty,
     }
 }
 
-/* Create a breakpoint with SAL as location.  Use ADDR_STRING
-   as textual description of the location, and COND_STRING
+/* Create a breakpoint with SAL as location.  Use LOCATION
+   as a description of the location, and COND_STRING
    as condition expression.  */
 
 static void
 init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
-		     struct symtabs_and_lines sals, char *addr_string,
+		     struct symtabs_and_lines sals,
+		     struct event_location *location,
 		     char *filter, char *cond_string,
 		     char *extra_string,
 		     enum bptype type, enum bpdisp disposition,
@@ -9138,7 +9162,10 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	  b->task = task;
 
 	  b->cond_string = cond_string;
-	  b->extra_string = extra_string;
+	  if (extra_string != NULL && *extra_string != '\0')
+	    b->extra_string = extra_string;
+	  else
+	    b->extra_string = NULL;
 	  b->ignore_count = ignore_count;
 	  b->enable_state = enabled ? bp_enabled : bp_disabled;
 	  b->disposition = disposition;
@@ -9155,13 +9182,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 		{
 		  /* We already know the marker exists, otherwise, we
 		     wouldn't see a sal for it.  */
-		  char *p = &addr_string[3];
-		  char *endp;
+		  const char *p = &event_location_to_string (b->location)[3];
+		  const char *endp;
 		  char *marker_str;
 
-		  p = skip_spaces (p);
+		  p = skip_spaces_const (p);
 
-		  endp = skip_to_space (p);
+		  endp = skip_to_space_const (p);
 
 		  marker_str = savestring (p, endp - p);
 		  t->static_trace_marker_id = marker_str;
@@ -9217,19 +9244,26 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
     }
 
   b->display_canonical = display_canonical;
-  if (addr_string)
-    b->addr_string = addr_string;
+  if (location != NULL)
+    b->location = location;
   else
-    /* addr_string has to be used or breakpoint_re_set will delete
-       me.  */
-    b->addr_string
-      = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+    {
+      char *tmp;
+      struct cleanup *cleanup;
+
+      tmp = xstrprintf ("*%s",
+			    paddress (b->loc->gdbarch, b->loc->address));
+      cleanup = make_cleanup (xfree, tmp);
+      b->location = new_linespec_location (&tmp);
+      do_cleanups (cleanup);
+   }
   b->filter = filter;
 }
 
 static void
 create_breakpoint_sal (struct gdbarch *gdbarch,
-		       struct symtabs_and_lines sals, char *addr_string,
+		       struct symtabs_and_lines sals,
+		       struct event_location *location,
 		       char *filter, char *cond_string,
 		       char *extra_string,
 		       enum bptype type, enum bpdisp disposition,
@@ -9254,7 +9288,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
   old_chain = make_cleanup (xfree, b);
 
   init_breakpoint_sal (b, gdbarch,
-		       sals, addr_string,
+		       sals, location,
 		       filter, cond_string, extra_string,
 		       type, disposition,
 		       thread, task, ignore_count,
@@ -9298,17 +9332,17 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 
   for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
     {
-      /* Note that 'addr_string' can be NULL in the case of a plain
+      /* Note that 'location' can be NULL in the case of a plain
 	 'break', without arguments.  */
-      char *addr_string = (canonical->addr_string
-			   ? xstrdup (canonical->addr_string)
-			   : NULL);
+      struct event_location *location
+	= (canonical->location != NULL
+	   ? copy_event_location (canonical->location) : NULL);
       char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
-      struct cleanup *inner = make_cleanup (xfree, addr_string);
+      struct cleanup *inner = make_cleanup_delete_event_location (location);
 
       make_cleanup (xfree, filter_string);
       create_breakpoint_sal (gdbarch, lsal->sals,
-			     addr_string,
+			     location,
 			     filter_string,
 			     cond_string, extra_string,
 			     type, disposition,
@@ -9319,83 +9353,97 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
     }
 }
 
-/* Parse ADDRESS which is assumed to be a SAL specification possibly
+/* Parse LOCATION which is assumed to be a SAL specification possibly
    followed by conditionals.  On return, SALS contains an array of SAL
-   addresses found.  ADDR_STRING contains a vector of (canonical)
-   address strings.  ADDRESS points to the end of the SAL.
+   addresses found.  LOCATION points to the end of the SAL (for
+   linespec locations).
 
    The array and the line spec strings are allocated on the heap, it is
    the caller's responsibility to free them.  */
 
 static void
-parse_breakpoint_sals (char **address,
+parse_breakpoint_sals (const struct event_location *location,
 		       struct linespec_result *canonical)
 {
-  /* If no arg given, or if first arg is 'if ', use the default
-     breakpoint.  */
-  if ((*address) == NULL || linespec_lexer_lex_keyword (*address))
-    {
-      /* The last displayed codepoint, if it's valid, is our default breakpoint
-         address.  */
-      if (last_displayed_sal_is_valid ())
-	{
-	  struct linespec_sals lsal;
-	  struct symtab_and_line sal;
-	  CORE_ADDR pc;
-
-	  init_sal (&sal);		/* Initialize to zeroes.  */
-	  lsal.sals.sals = (struct symtab_and_line *)
-	    xmalloc (sizeof (struct symtab_and_line));
-
-	  /* Set sal's pspace, pc, symtab, and line to the values
-	     corresponding to the last call to print_frame_info.
-	     Be sure to reinitialize LINE with NOTCURRENT == 0
-	     as the breakpoint line number is inappropriate otherwise.
-	     find_pc_line would adjust PC, re-set it back.  */
-	  get_last_displayed_sal (&sal);
-	  pc = sal.pc;
-	  sal = find_pc_line (pc, 0);
-
-	  /* "break" without arguments is equivalent to "break *PC"
-	     where PC is the last displayed codepoint's address.  So
-	     make sure to set sal.explicit_pc to prevent GDB from
-	     trying to expand the list of sals to include all other
-	     instances with the same symtab and line.  */
-	  sal.pc = pc;
-	  sal.explicit_pc = 1;
-
-	  lsal.sals.sals[0] = sal;
-	  lsal.sals.nelts = 1;
-	  lsal.canonical = NULL;
-
-	  VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+  struct symtab_and_line cursal;
+
+  if (event_location_type (location) == LINESPEC_LOCATION)
+    {
+      const char *address = get_linespec_location (location);
+
+      if (address == NULL)
+	{
+	  /* The last displayed codepoint, if it's valid, is our default
+	     breakpoint address.  */
+	  if (last_displayed_sal_is_valid ())
+	    {
+	      struct linespec_sals lsal;
+	      struct symtab_and_line sal;
+	      CORE_ADDR pc;
+
+	      init_sal (&sal);		/* Initialize to zeroes.  */
+	      lsal.sals.sals = (struct symtab_and_line *)
+		xmalloc (sizeof (struct symtab_and_line));
+
+	      /* Set sal's pspace, pc, symtab, and line to the values
+		 corresponding to the last call to print_frame_info.
+		 Be sure to reinitialize LINE with NOTCURRENT == 0
+		 as the breakpoint line number is inappropriate otherwise.
+		 find_pc_line would adjust PC, re-set it back.  */
+	      get_last_displayed_sal (&sal);
+	      pc = sal.pc;
+	      sal = find_pc_line (pc, 0);
+
+	      /* "break" without arguments is equivalent to "break *PC"
+		 where PC is the last displayed codepoint's address.  So
+		 make sure to set sal.explicit_pc to prevent GDB from
+		 trying to expand the list of sals to include all other
+		 instances with the same symtab and line.  */
+	      sal.pc = pc;
+	      sal.explicit_pc = 1;
+
+	      lsal.sals.sals[0] = sal;
+	      lsal.sals.nelts = 1;
+	      lsal.canonical = NULL;
+
+	      VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+	      return;
+	    }
+	  else
+	    error (_("No default breakpoint address now."));
 	}
-      else
-	error (_("No default breakpoint address now."));
     }
-  else
+
+  /* Force almost all breakpoints to be in terms of the
+     current_source_symtab (which is decode_line_1's default).
+     This should produce the results we want almost all of the
+     time while leaving default_breakpoint_* alone.
+
+     ObjC: However, don't match an Objective-C method name which
+     may have a '+' or '-' succeeded by a '['.  */
+  cursal = get_current_source_symtab_and_line ();
+  if (last_displayed_sal_is_valid ())
     {
-      struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+      const char *address = NULL;
 
-      /* Force almost all breakpoints to be in terms of the
-         current_source_symtab (which is decode_line_1's default).
-         This should produce the results we want almost all of the
-         time while leaving default_breakpoint_* alone.
+      if (event_location_type (location) == LINESPEC_LOCATION)
+	address = get_linespec_location (location);
 
-	 ObjC: However, don't match an Objective-C method name which
-	 may have a '+' or '-' succeeded by a '['.  */
-      if (last_displayed_sal_is_valid ()
-	  && (!cursal.symtab
-	      || ((strchr ("+-", (*address)[0]) != NULL)
-		  && ((*address)[1] != '['))))
-	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
-			  get_last_displayed_symtab (),
-			  get_last_displayed_line (),
-			  canonical, NULL, NULL);
-      else
-	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
-			  cursal.symtab, cursal.line, canonical, NULL, NULL);
+      if (!cursal.symtab
+	  || (address != NULL
+	      && strchr ("+-", address[0]) != NULL
+	      && address[1] != '['))
+	{
+	  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
+			    get_last_displayed_symtab (),
+			    get_last_displayed_line (),
+			    canonical, NULL, NULL);
+	  return;
+	}
     }
+
+  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
+		    cursal.symtab, cursal.line, canonical, NULL, NULL);
 }
 
 
@@ -9541,19 +9589,19 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
 /* Decode a static tracepoint marker spec.  */
 
 static struct symtabs_and_lines
-decode_static_tracepoint_spec (char **arg_p)
+decode_static_tracepoint_spec (const char **arg_p)
 {
   VEC(static_tracepoint_marker_p) *markers = NULL;
   struct symtabs_and_lines sals;
   struct cleanup *old_chain;
-  char *p = &(*arg_p)[3];
-  char *endp;
+  const char *p = &(*arg_p)[3];
+  const char *endp;
   char *marker_str;
   int i;
 
-  p = skip_spaces (p);
+  p = skip_spaces_const (p);
 
-  endp = skip_to_space (p);
+  endp = skip_to_space_const (p);
 
   marker_str = savestring (p, endp - p);
   old_chain = make_cleanup (xfree, marker_str);
@@ -9585,22 +9633,13 @@ decode_static_tracepoint_spec (char **arg_p)
   return sals;
 }
 
-/* Set a breakpoint.  This function is shared between CLI and MI
-   functions for setting a breakpoint.  This function has two major
-   modes of operations, selected by the PARSE_ARG parameter.  If
-   non-zero, the function will parse ARG, extracting location,
-   condition, thread and extra string.  Otherwise, ARG is just the
-   breakpoint's location, with condition, thread, and extra string
-   specified by the COND_STRING, THREAD and EXTRA_STRING parameters.
-   If INTERNAL is non-zero, the breakpoint number will be allocated
-   from the internal breakpoint count.  Returns true if any breakpoint
-   was created; false otherwise.  */
+/* See breakpoint.h.  */
 
 int
 create_breakpoint (struct gdbarch *gdbarch,
-		   char *arg, char *cond_string,
+		   const struct event_location *location, char *cond_string,
 		   int thread, char *extra_string,
-		   int parse_arg,
+		   int parse_extra,
 		   int tempflag, enum bptype type_wanted,
 		   int ignore_count,
 		   enum auto_boolean pending_break_support,
@@ -9608,8 +9647,6 @@ create_breakpoint (struct gdbarch *gdbarch,
 		   int from_tty, int enabled, int internal,
 		   unsigned flags)
 {
-  char *copy_arg = NULL;
-  char *addr_start = arg;
   struct linespec_result canonical;
   struct cleanup *old_chain;
   struct cleanup *bkpt_chain = NULL;
@@ -9619,12 +9656,15 @@ create_breakpoint (struct gdbarch *gdbarch,
 
   gdb_assert (ops != NULL);
 
+  /* If extra_string isn't useful, set it to NULL.  */
+  if (extra_string != NULL && *extra_string == '\0')
+    extra_string = NULL;
+
   init_linespec_result (&canonical);
 
   TRY
     {
-      ops->create_sals_from_location (&arg, &canonical, type_wanted,
-				      addr_start, &copy_arg);
+      ops->create_sals_from_location (location, &canonical, type_wanted);
     }
   CATCH (e, RETURN_MASK_ERROR)
     {
@@ -9651,24 +9691,14 @@ create_breakpoint (struct gdbarch *gdbarch,
 	     a pending breakpoint and selected yes, or pending
 	     breakpoint behavior is on and thus a pending breakpoint
 	     is defaulted on behalf of the user.  */
-	  {
-	    struct linespec_sals lsal;
-
-	    copy_arg = xstrdup (addr_start);
-	    lsal.canonical = xstrdup (copy_arg);
-	    lsal.sals.nelts = 1;
-	    lsal.sals.sals = XNEW (struct symtab_and_line);
-	    init_sal (&lsal.sals.sals[0]);
-	    pending = 1;
-	    VEC_safe_push (linespec_sals, canonical.sals, &lsal);
-	  }
+	  pending = 1;
 	}
       else
 	throw_exception (e);
     }
   END_CATCH
 
-  if (VEC_empty (linespec_sals, canonical.sals))
+  if (!pending && VEC_empty (linespec_sals, canonical.sals))
     return 0;
 
   /* Create a chain of things that always need to be cleaned up.  */
@@ -9706,7 +9736,7 @@ create_breakpoint (struct gdbarch *gdbarch,
      breakpoint.  */
   if (!pending)
     {
-      if (parse_arg)
+      if (parse_extra)
         {
 	  char *rest;
 	  struct linespec_sals *lsal;
@@ -9718,19 +9748,22 @@ create_breakpoint (struct gdbarch *gdbarch,
 	     sal is OK.  When setting the breakpoint we'll
 	     re-parse it in context of each sal.  */
 
-	  find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
-				     &thread, &task, &rest);
+	  find_condition_and_thread (extra_string, lsal->sals.sals[0].pc,
+				     &cond_string, &thread, &task, &rest);
 	  if (cond_string)
 	    make_cleanup (xfree, cond_string);
 	  if (rest)
 	    make_cleanup (xfree, rest);
 	  if (rest)
 	    extra_string = rest;
+	  else
+	    extra_string = NULL;
         }
       else
         {
-	  if (*arg != '\0')
-	    error (_("Garbage '%s' at end of location"), arg);
+	  if (type_wanted != bp_dprintf
+	      && extra_string != NULL && *extra_string != '\0')
+		error (_("Garbage '%s' at end of location"), extra_string);
 
 	  /* Create a private copy of condition string.  */
 	  if (cond_string)
@@ -9756,8 +9789,6 @@ create_breakpoint (struct gdbarch *gdbarch,
     {
       struct breakpoint *b;
 
-      make_cleanup (xfree, copy_arg);
-
       if (is_tracepoint_type (type_wanted))
 	{
 	  struct tracepoint *t;
@@ -9769,9 +9800,22 @@ create_breakpoint (struct gdbarch *gdbarch,
 	b = XNEW (struct breakpoint);
 
       init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
+      b->location = copy_event_location (location);
+
+      /* Append extra_string, if set, to the canonical representation
+	 of the lsal.  This preserves any conditions that the user may
+	 have specified.  */
+      if (extra_string != NULL)
+	{
+	  char *new = xstrprintf ("%s %s",
+				  event_location_to_string_const (location),
+				  extra_string);
 
-      b->addr_string = copy_arg;
-      if (parse_arg)
+	  set_event_location_string (b->location, new);
+	  xfree (new);
+	}
+
+      if (parse_extra)
 	b->cond_string = NULL;
       else
 	{
@@ -9784,7 +9828,14 @@ create_breakpoint (struct gdbarch *gdbarch,
 	  b->cond_string = cond_string;
 	  b->thread = thread;
 	}
-      b->extra_string = NULL;
+
+      /* Make a private copy of extra_string for the breakpoint.  */
+      if (extra_string != NULL)
+	{
+	  extra_string = xstrdup (extra_string);
+	  make_cleanup (xfree, extra_string);
+	}
+      b->extra_string =  extra_string;
       b->ignore_count = ignore_count;
       b->disposition = tempflag ? disp_del : disp_donttouch;
       b->condition_not_parsed = 1;
@@ -9831,16 +9882,21 @@ break_command_1 (char *arg, int flag, int from_tty)
 			     : bp_breakpoint);
   struct breakpoint_ops *ops;
   const char *arg_cp = arg;
+  struct event_location *location;
+  struct cleanup *cleanup;
+
+  location = string_to_event_location (&arg, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
 
   /* Matching breakpoints on probes.  */
-  if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
+  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
     ops = &bkpt_probe_breakpoint_ops;
   else
     ops = &bkpt_breakpoint_ops;
 
   create_breakpoint (get_current_arch (),
-		     arg,
-		     NULL, 0, NULL, 1 /* parse arg */,
+		     location,
+		     NULL, 0, arg, 1 /* parse arg */,
 		     tempflag, type_wanted,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -9849,6 +9905,7 @@ break_command_1 (char *arg, int flag, int from_tty)
 		     1 /* enabled */,
 		     0 /* internal */,
 		     0);
+  do_cleanups (cleanup);
 }
 
 /* Helper function for break_command_1 and disassemble_command.  */
@@ -10015,9 +10072,15 @@ stopat_command (char *arg, int from_tty)
 static void
 dprintf_command (char *arg, int from_tty)
 {
+  struct event_location *location;
+  struct cleanup *cleanup;
+
+  location = string_to_event_location (&arg, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
+
   create_breakpoint (get_current_arch (),
-		     arg,
-		     NULL, 0, NULL, 1 /* parse arg */,
+		     location,
+		     NULL, 0, arg, 1 /* parse arg */,
 		     0, bp_dprintf,
 		     0 /* Ignore count */,
 		     pending_break_support,
@@ -10026,6 +10089,7 @@ dprintf_command (char *arg, int from_tty)
 		     1 /* enabled */,
 		     0 /* internal */,
 		     0);
+  do_cleanups (cleanup);
 }
 
 static void
@@ -10170,8 +10234,9 @@ print_mention_ranged_breakpoint (struct breakpoint *b)
 static void
 print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
 {
-  fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
-		      b->addr_string_range_end);
+  fprintf_unfiltered (fp, "break-range %s, %s",
+		      event_location_to_string (b->location),
+		      event_location_to_string (b->location_range_end));
   print_recreate_thread (b, fp);
 }
 
@@ -10222,6 +10287,7 @@ break_range_command (char *arg, int from_tty)
   struct symtab_and_line sal_start, sal_end;
   struct cleanup *cleanup_bkpt;
   struct linespec_sals *lsal_start, *lsal_end;
+  struct event_location *start_location, *end_location;
 
   /* We don't support software ranged breakpoints.  */
   if (target_ranged_break_num_registers () < 0)
@@ -10241,9 +10307,10 @@ break_range_command (char *arg, int from_tty)
   init_linespec_result (&canonical_start);
 
   arg_start = arg;
-  parse_breakpoint_sals (&arg, &canonical_start);
-
-  cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
+  start_location = string_to_event_location (&arg, current_language);
+  cleanup_bkpt = make_cleanup_delete_event_location (start_location);
+  parse_breakpoint_sals (start_location, &canonical_start);
+  make_cleanup_destroy_linespec_result (&canonical_start);
 
   if (arg[0] != ',')
     error (_("Too few arguments."));
@@ -10273,7 +10340,9 @@ break_range_command (char *arg, int from_tty)
      symtab and line as the default symtab and line for the end of the
      range.  This makes it possible to have ranges like "foo.c:27, +14",
      where +14 means 14 lines from the start location.  */
-  decode_line_full (&arg, DECODE_LINE_FUNFIRSTLINE,
+  end_location = string_to_event_location (&arg, current_language);
+  make_cleanup_delete_event_location (end_location);
+  decode_line_full (end_location, DECODE_LINE_FUNFIRSTLINE,
 		    sal_start.symtab, sal_start.line,
 		    &canonical_end, NULL, NULL);
 
@@ -10288,8 +10357,6 @@ break_range_command (char *arg, int from_tty)
     error (_("Cannot create a ranged breakpoint with multiple locations."));
 
   sal_end = lsal_end->sals.sals[0];
-  addr_string_end = savestring (arg_start, arg - arg_start);
-  make_cleanup (xfree, addr_string_end);
 
   end = find_breakpoint_range_end (sal_end);
   if (sal_start.pc > end)
@@ -10316,8 +10383,8 @@ break_range_command (char *arg, int from_tty)
   set_breakpoint_count (breakpoint_count + 1);
   b->number = breakpoint_count;
   b->disposition = disp_donttouch;
-  b->addr_string = xstrdup (addr_string_start);
-  b->addr_string_range_end = xstrdup (addr_string_end);
+  b->location = copy_event_location (start_location);
+  b->location_range_end = copy_event_location (end_location);
   b->loc->length = length;
 
   do_cleanups (cleanup_bkpt);
@@ -11444,21 +11511,25 @@ until_break_command (char *arg, int from_tty, int anywhere)
   struct frame_id caller_frame_id;
   struct breakpoint *breakpoint;
   struct breakpoint *breakpoint2 = NULL;
-  struct cleanup *old_chain;
+  struct cleanup *old_chain, *cleanup;
   int thread;
   struct thread_info *tp;
+  struct event_location *location;
 
   clear_proceed_status (0);
 
   /* Set a breakpoint where the user wants it and at return from
      this function.  */
 
+  location = string_to_event_location (&arg, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
+
   if (last_displayed_sal_is_valid ())
-    sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE,
+    sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
 			  get_last_displayed_symtab (),
 			  get_last_displayed_line ());
   else
-    sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE,
+    sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
 			  (struct symtab *) NULL, 0);
 
   if (sals.nelts != 1)
@@ -11544,6 +11615,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
     }
   else
     do_cleanups (old_chain);
+
+  do_cleanups (cleanup);
 }
 
 /* This function attempts to parse an optional "if <cond>" clause
@@ -11699,7 +11772,8 @@ init_ada_exception_breakpoint (struct breakpoint *b,
 
   b->enable_state = enabled ? bp_enabled : bp_disabled;
   b->disposition = tempflag ? disp_del : disp_donttouch;
-  b->addr_string = addr_string;
+  b->location = string_to_event_location (&addr_string,
+					  language_def (language_ada));
   b->language = language_ada;
 }
 
@@ -12569,7 +12643,8 @@ say_where (struct breakpoint *b)
      single string.  */
   if (b->loc == NULL)
     {
-      printf_filtered (_(" (%s) pending."), b->addr_string);
+      printf_filtered (_(" (%s) pending."),
+		       event_location_to_string (b->location));
     }
   else
     {
@@ -12591,7 +12666,8 @@ say_where (struct breakpoint *b)
 	    /* This is not ideal, but each location may have a
 	       different file name, and this at least reflects the
 	       real situation somewhat.  */
-	    printf_filtered (": %s.", b->addr_string);
+	    printf_filtered (": %s.",
+			     event_location_to_string (b->location));
 	}
 
       if (b->loc->next)
@@ -12633,9 +12709,9 @@ base_breakpoint_dtor (struct breakpoint *self)
   decref_counted_command_line (&self->commands);
   xfree (self->cond_string);
   xfree (self->extra_string);
-  xfree (self->addr_string);
   xfree (self->filter);
-  xfree (self->addr_string_range_end);
+  delete_event_location (self->location);
+  delete_event_location (self->location_range_end);
 }
 
 static struct bp_location *
@@ -12728,11 +12804,10 @@ base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
 }
 
 static void
-base_breakpoint_create_sals_from_location (char **arg,
-					   struct linespec_result *canonical,
-					   enum bptype type_wanted,
-					   char *addr_start,
-					   char **copy_arg)
+base_breakpoint_create_sals_from_location
+  (const struct event_location *location,
+   struct linespec_result *canonical,
+   enum bptype type_wanted)
 {
   internal_error_pure_virtual_called ();
 }
@@ -12754,7 +12829,8 @@ base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-base_breakpoint_decode_location (struct breakpoint *b, char **s,
+base_breakpoint_decode_location (struct breakpoint *b,
+				 const struct event_location *location,
 				 struct symtabs_and_lines *sals)
 {
   internal_error_pure_virtual_called ();
@@ -12805,9 +12881,9 @@ static void
 bkpt_re_set (struct breakpoint *b)
 {
   /* FIXME: is this still reachable?  */
-  if (b->addr_string == NULL)
+  if (event_location_empty_p (b->location))
     {
-      /* Anything without a string can't be re-set.  */
+      /* Anything without a location can't be re-set.  */
       delete_breakpoint (b);
       return;
     }
@@ -12959,18 +13035,17 @@ bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
     internal_error (__FILE__, __LINE__,
 		    _("unhandled breakpoint type %d"), (int) tp->type);
 
-  fprintf_unfiltered (fp, " %s", tp->addr_string);
+  fprintf_unfiltered (fp, " %s",
+		      event_location_to_string (tp->location));
   print_recreate_thread (tp, fp);
 }
 
 static void
-bkpt_create_sals_from_location (char **arg,
-			       struct linespec_result *canonical,
-			       enum bptype type_wanted,
-			       char *addr_start, char **copy_arg)
+bkpt_create_sals_from_location (const struct event_location *location,
+				struct linespec_result *canonical,
+				enum bptype type_wanted)
 {
-  create_sals_from_location_default (arg, canonical, type_wanted,
-				    addr_start, copy_arg);
+  create_sals_from_location_default (location, canonical, type_wanted);
 }
 
 static void
@@ -12995,10 +13070,11 @@ bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-bkpt_decode_location (struct breakpoint *b, char **s,
+bkpt_decode_location (struct breakpoint *b,
+		      const struct event_location *location,
 		      struct symtabs_and_lines *sals)
 {
-  decode_location_default (b, s, sals);
+  decode_location_default (b, location, sals);
 }
 
 /* Virtual table for internal breakpoints.  */
@@ -13198,26 +13274,23 @@ bkpt_probe_remove_location (struct bp_location *bl)
 }
 
 static void
-bkpt_probe_create_sals_from_location (char **arg,
+bkpt_probe_create_sals_from_location (const struct event_location *location,
 				      struct linespec_result *canonical,
-				      enum bptype type_wanted,
-				      char *addr_start, char **copy_arg)
+				      enum bptype type_wanted)
 {
   struct linespec_sals lsal;
 
-  lsal.sals = parse_probes (arg, canonical);
-
-  *copy_arg = xstrdup (canonical->addr_string);
-  lsal.canonical = xstrdup (*copy_arg);
-
+  lsal.sals = parse_probes (location, canonical);
+  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
   VEC_safe_push (linespec_sals, canonical->sals, &lsal);
 }
 
 static void
-bkpt_probe_decode_location (struct breakpoint *b, char **s,
+bkpt_probe_decode_location (struct breakpoint *b,
+			    const struct event_location *location,
 			    struct symtabs_and_lines *sals)
 {
-  *sals = parse_probes (s, NULL);
+  *sals = parse_probes (location, NULL);
   if (!sals->sals)
     error (_("probe not found"));
 }
@@ -13299,7 +13372,8 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
     internal_error (__FILE__, __LINE__,
 		    _("unhandled tracepoint type %d"), (int) self->type);
 
-  fprintf_unfiltered (fp, " %s", self->addr_string);
+  fprintf_unfiltered (fp, " %s",
+		      event_location_to_string (self->location));
   print_recreate_thread (self, fp);
 
   if (tp->pass_count)
@@ -13307,13 +13381,11 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
 }
 
 static void
-tracepoint_create_sals_from_location (char **arg,
-				     struct linespec_result *canonical,
-				     enum bptype type_wanted,
-				     char *addr_start, char **copy_arg)
+tracepoint_create_sals_from_location (const struct event_location *location,
+				      struct linespec_result *canonical,
+				      enum bptype type_wanted)
 {
-  create_sals_from_location_default (arg, canonical, type_wanted,
-				    addr_start, copy_arg);
+  create_sals_from_location_default (location, canonical, type_wanted);
 }
 
 static void
@@ -13338,10 +13410,11 @@ tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-tracepoint_decode_location (struct breakpoint *b, char **s,
+tracepoint_decode_location (struct breakpoint *b,
+			    const struct event_location *location,
 			    struct symtabs_and_lines *sals)
 {
-  decode_location_default (b, s, sals);
+  decode_location_default (b, location, sals);
 }
 
 struct breakpoint_ops tracepoint_breakpoint_ops;
@@ -13350,22 +13423,22 @@ struct breakpoint_ops tracepoint_breakpoint_ops;
    static probe.  */
 
 static void
-tracepoint_probe_create_sals_from_location (char **arg,
-					    struct linespec_result *canonical,
-					    enum bptype type_wanted,
-					    char *addr_start, char **copy_arg)
+tracepoint_probe_create_sals_from_location
+  (const struct event_location *location,
+   struct linespec_result *canonical,
+   enum bptype type_wanted)
 {
   /* We use the same method for breakpoint on probes.  */
-  bkpt_probe_create_sals_from_location (arg, canonical, type_wanted,
-					addr_start, copy_arg);
+  bkpt_probe_create_sals_from_location (location, canonical, type_wanted);
 }
 
 static void
-tracepoint_probe_decode_location (struct breakpoint *b, char **s,
+tracepoint_probe_decode_location (struct breakpoint *b,
+				  const struct event_location *location,
 				  struct symtabs_and_lines *sals)
 {
   /* We use the same method for breakpoint on probes.  */
-  bkpt_probe_decode_location (b, s, sals);
+  bkpt_probe_decode_location (b, location, sals);
 }
 
 static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
@@ -13404,7 +13477,8 @@ dprintf_re_set (struct breakpoint *b)
 static void
 dprintf_print_recreate (struct breakpoint *tp, struct ui_file *fp)
 {
-  fprintf_unfiltered (fp, "dprintf %s%s", tp->addr_string,
+  fprintf_unfiltered (fp, "dprintf %s%s",
+		      event_location_to_string (tp->location),
 		      tp->extra_string);
   print_recreate_thread (tp, fp);
 }
@@ -13451,19 +13525,28 @@ dprintf_after_condition_true (struct bpstats *bs)
    markers (`-m').  */
 
 static void
-strace_marker_create_sals_from_location (char **arg,
+strace_marker_create_sals_from_location (const struct event_location *location,
 					 struct linespec_result *canonical,
-					 enum bptype type_wanted,
-					 char *addr_start, char **copy_arg)
+					 enum bptype type_wanted)
 {
   struct linespec_sals lsal;
+  const char *arg_start, *arg;
 
-  lsal.sals = decode_static_tracepoint_spec (arg);
+  arg = arg_start = get_linespec_location (location);
+  lsal.sals = decode_static_tracepoint_spec (&arg);
 
-  *copy_arg = savestring (addr_start, *arg - addr_start);
+  if (canonical != NULL)
+    {
+      char *str;
+      struct cleanup *cleanup;
 
-  canonical->addr_string = xstrdup (*copy_arg);
-  lsal.canonical = xstrdup (*copy_arg);
+      str = savestring (arg_start, arg - arg_start);
+      cleanup = make_cleanup (xfree, str);
+      canonical->location = new_linespec_location (&str);
+      do_cleanups (cleanup);
+    }
+
+  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
   VEC_safe_push (linespec_sals, canonical->sals, &lsal);
 }
 
@@ -13496,17 +13579,17 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
       struct symtabs_and_lines expanded;
       struct tracepoint *tp;
       struct cleanup *old_chain;
-      char *addr_string;
+      struct event_location *location;
 
       expanded.nelts = 1;
       expanded.sals = &lsal->sals.sals[i];
 
-      addr_string = xstrdup (canonical->addr_string);
-      old_chain = make_cleanup (xfree, addr_string);
+      location = copy_event_location (canonical->location);
+      old_chain = make_cleanup_delete_event_location (location);
 
       tp = XCNEW (struct tracepoint);
       init_breakpoint_sal (&tp->base, gdbarch, expanded,
-			   addr_string, NULL,
+			   location, NULL,
 			   cond_string, extra_string,
 			   type_wanted, disposition,
 			   thread, task, ignore_count, ops,
@@ -13527,12 +13610,14 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-strace_marker_decode_location (struct breakpoint *b, char **s,
+strace_marker_decode_location (struct breakpoint *b,
+			       const struct event_location *location,
 			       struct symtabs_and_lines *sals)
 {
   struct tracepoint *tp = (struct tracepoint *) b;
+  const char *s = get_linespec_location (location);
 
-  *sals = decode_static_tracepoint_spec (s);
+  *sals = decode_static_tracepoint_spec (&s);
   if (sals->nelts > tp->static_trace_marker_id_idx)
     {
       sals->sals[0] = sals->sals[tp->static_trace_marker_id_idx];
@@ -13864,10 +13949,12 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 
       if (!VEC_empty(static_tracepoint_marker_p, markers))
 	{
+	  char *p, *tmp;
 	  struct symtab_and_line sal2;
 	  struct symbol *sym;
 	  struct static_tracepoint_marker *tpmarker;
 	  struct ui_out *uiout = current_uiout;
+	  struct cleanup *cleanup;
 
 	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
 
@@ -13908,10 +13995,13 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 	  b->loc->line_number = sal2.line;
 	  b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
 
-	  xfree (b->addr_string);
-	  b->addr_string = xstrprintf ("%s:%d",
-				   symtab_to_filename_for_display (sal2.symtab),
-				       b->loc->line_number);
+	  delete_event_location (b->location);
+	  p = tmp = xstrprintf ("%s:%d",
+				symtab_to_filename_for_display (sal2.symtab),
+				b->loc->line_number);
+	  cleanup = make_cleanup (xfree, tmp);
+	  b->location = new_linespec_location (&tmp);
+	  do_cleanups (cleanup);
 
 	  /* Might be nice to check if function changed, and warn if
 	     so.  */
@@ -14068,22 +14158,21 @@ update_breakpoint_locations (struct breakpoint *b,
   update_global_location_list (UGLL_MAY_INSERT);
 }
 
-/* Find the SaL locations corresponding to the given ADDR_STRING.
+/* Find the SaL locations corresponding to the given LOCATION.
    On return, FOUND will be 1 if any SaL was found, zero otherwise.  */
 
 static struct symtabs_and_lines
-location_to_sals (struct breakpoint *b, char *addr_string, int *found)
+location_to_sals (struct breakpoint *b, struct event_location *location,
+		  int *found)
 {
-  char *s;
   struct symtabs_and_lines sals = {0};
   struct gdb_exception exception = exception_none;
 
   gdb_assert (b->ops != NULL);
-  s = addr_string;
 
   TRY
     {
-      b->ops->decode_location (b, &s, &sals);
+      b->ops->decode_location (b, location, &sals);
     }
   CATCH (e, RETURN_MASK_ERROR)
     {
@@ -14125,12 +14214,13 @@ location_to_sals (struct breakpoint *b, char *addr_string, int *found)
 
       for (i = 0; i < sals.nelts; ++i)
 	resolve_sal_pc (&sals.sals[i]);
-      if (b->condition_not_parsed && s && s[0])
+      if (b->condition_not_parsed && b->extra_string != NULL)
 	{
 	  char *cond_string, *extra_string;
 	  int thread, task;
+	  const char *orig = b->extra_string;
 
-	  find_condition_and_thread (s, sals.sals[0].pc,
+	  find_condition_and_thread (b->extra_string, sals.sals[0].pc,
 				     &cond_string, &thread, &task,
 				     &extra_string);
 	  if (cond_string)
@@ -14138,8 +14228,18 @@ location_to_sals (struct breakpoint *b, char *addr_string, int *found)
 	  b->thread = thread;
 	  b->task = task;
 	  if (extra_string)
-	    b->extra_string = extra_string;
+	    {
+	      xfree (b->extra_string);
+	      b->extra_string = extra_string;
+	    }
 	  b->condition_not_parsed = 0;
+
+	  /* If the breakpoint was pending and is now resolved,
+	     clear the location's string representation.  This
+	     is necessary since pending breakpoints may have
+	     condition, thread, or task keywords embedded into it.  */
+	  if (b->loc == NULL)
+	    set_event_location_string (b->location, NULL);
 	}
 
       if (b->type == bp_static_tracepoint && !strace_marker_p (b))
@@ -14165,16 +14265,16 @@ breakpoint_re_set_default (struct breakpoint *b)
   struct symtabs_and_lines expanded = {0};
   struct symtabs_and_lines expanded_end = {0};
 
-  sals = location_to_sals (b, b->addr_string, &found);
+  sals = location_to_sals (b, b->location, &found);
   if (found)
     {
       make_cleanup (xfree, sals.sals);
       expanded = sals;
     }
 
-  if (b->addr_string_range_end)
+  if (b->location_range_end != NULL)
     {
-      sals_end = location_to_sals (b, b->addr_string_range_end, &found);
+      sals_end = location_to_sals (b, b->location_range_end, &found);
       if (found)
 	{
 	  make_cleanup (xfree, sals_end.sals);
@@ -14189,12 +14289,11 @@ breakpoint_re_set_default (struct breakpoint *b)
    calls parse_breakpoint_sals.  Return 1 for success, zero for failure.  */
 
 static void
-create_sals_from_location_default (char **arg,
-				  struct linespec_result *canonical,
-				  enum bptype type_wanted,
-				  char *addr_start, char **copy_arg)
+create_sals_from_location_default (const struct event_location *location,
+				   struct linespec_result *canonical,
+				   enum bptype type_wanted)
 {
-  parse_breakpoint_sals (arg, canonical);
+  parse_breakpoint_sals (location, canonical);
 }
 
 /* Call create_breakpoints_sal for the given arguments.  This is the default
@@ -14225,13 +14324,14 @@ create_breakpoints_sal_default (struct gdbarch *gdbarch,
    default function for the `decode_location' method of breakpoint_ops.  */
 
 static void
-decode_location_default (struct breakpoint *b, char **s,
+decode_location_default (struct breakpoint *b,
+			 const struct event_location *location,
 			 struct symtabs_and_lines *sals)
 {
   struct linespec_result canonical;
 
   init_linespec_result (&canonical);
-  decode_line_full (s, DECODE_LINE_FUNFIRSTLINE,
+  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
 		    (struct symtab *) NULL, 0,
 		    &canonical, multiple_symbols_all,
 		    b->filter);
@@ -14903,16 +15003,20 @@ static void
 trace_command (char *arg, int from_tty)
 {
   struct breakpoint_ops *ops;
+  struct event_location *location;
+  struct cleanup *back_to;
   const char *arg_cp = arg;
 
-  if (arg && probe_linespec_to_ops (&arg_cp))
+  location = string_to_event_location (&arg, current_language);
+  back_to = make_cleanup_delete_event_location (location);
+  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
     ops = &tracepoint_probe_breakpoint_ops;
   else
     ops = &tracepoint_breakpoint_ops;
 
   create_breakpoint (get_current_arch (),
-		     arg,
-		     NULL, 0, NULL, 1 /* parse arg */,
+		     location,
+		     NULL, 0, arg, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14921,14 +15025,20 @@ trace_command (char *arg, int from_tty)
 		     from_tty,
 		     1 /* enabled */,
 		     0 /* internal */, 0);
+  do_cleanups (back_to);
 }
 
 static void
 ftrace_command (char *arg, int from_tty)
 {
+  struct event_location *location;
+  struct cleanup *back_to;
+
+  location = string_to_event_location (&arg, current_language);
+  back_to = make_cleanup_delete_event_location (location);
   create_breakpoint (get_current_arch (),
-		     arg,
-		     NULL, 0, NULL, 1 /* parse arg */,
+		     location,
+		     NULL, 0, arg, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_fast_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14937,6 +15047,7 @@ ftrace_command (char *arg, int from_tty)
 		     from_tty,
 		     1 /* enabled */,
 		     0 /* internal */, 0);
+  do_cleanups (back_to);
 }
 
 /* strace command implementation.  Creates a static tracepoint.  */
@@ -14945,17 +15056,26 @@ static void
 strace_command (char *arg, int from_tty)
 {
   struct breakpoint_ops *ops;
+  struct event_location *location;
+  struct cleanup *back_to;
 
   /* Decide if we are dealing with a static tracepoint marker (`-m'),
      or with a normal static tracepoint.  */
   if (arg && startswith (arg, "-m") && isspace (arg[2]))
-    ops = &strace_marker_breakpoint_ops;
+    {
+      ops = &strace_marker_breakpoint_ops;
+      location = new_linespec_location (&arg);
+    }
   else
-    ops = &tracepoint_breakpoint_ops;
+    {
+      ops = &tracepoint_breakpoint_ops;
+      location = string_to_event_location (&arg, current_language);
+    }
 
+  back_to = make_cleanup_delete_event_location (location);
   create_breakpoint (get_current_arch (),
-		     arg,
-		     NULL, 0, NULL, 1 /* parse arg */,
+		     location,
+		     NULL, 0, arg, 1 /* parse arg */,
 		     0 /* tempflag */,
 		     bp_static_tracepoint /* type_wanted */,
 		     0 /* Ignore count */,
@@ -14964,6 +15084,7 @@ strace_command (char *arg, int from_tty)
 		     from_tty,
 		     1 /* enabled */,
 		     0 /* internal */, 0);
+  do_cleanups (back_to);
 }
 
 /* Set up a fake reader function that gets command lines from a linked
@@ -14995,6 +15116,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 {
   char *addr_str, small_buf[100];
   struct tracepoint *tp;
+  struct event_location *location;
+  struct cleanup *cleanup;
 
   if (utp->at_string)
     addr_str = utp->at_string;
@@ -15017,9 +15140,11 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 	       "has no source form, ignoring it"),
 	     utp->number);
 
+  location = string_to_event_location (&addr_str, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
   if (!create_breakpoint (get_current_arch (),
-			  addr_str,
-			  utp->cond_string, -1, NULL,
+			  location,
+			  utp->cond_string, -1, addr_str,
 			  0 /* parse cond/thread */,
 			  0 /* tempflag */,
 			  utp->type /* type_wanted */,
@@ -15030,7 +15155,12 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 			  utp->enabled /* enabled */,
 			  0 /* internal */,
 			  CREATE_BREAKPOINT_FLAGS_INSERTED))
-    return NULL;
+    {
+      do_cleanups (cleanup);
+      return NULL;
+    }
+
+  do_cleanups (cleanup);
 
   /* Get the tracepoint we just created.  */
   tp = get_tracepoint (tracepoint_count);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 6f144bd..8921bf0 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -37,6 +37,7 @@ struct bpstats;
 struct bp_location;
 struct linespec_result;
 struct linespec_sals;
+struct event_location;
 
 /* This is the maximum number of bytes a breakpoint instruction can
    take.  Feel free to increase it.  It's just used in a few places to
@@ -580,8 +581,9 @@ struct breakpoint_ops
      `create_sals_from_location_default'.
 
      This function is called inside `create_breakpoint'.  */
-  void (*create_sals_from_location) (char **, struct linespec_result *,
-				     enum bptype, char *, char **);
+  void (*create_sals_from_location) (const struct event_location *location,
+				     struct linespec_result *canonical,
+				     enum bptype type_wanted);
 
   /* This method will be responsible for creating a breakpoint given its SALs.
      Usually, it just calls `create_breakpoints_sal' (for ordinary
@@ -602,8 +604,9 @@ struct breakpoint_ops
      it calls `decode_line_full'.
 
      This function is called inside `location_to_sals'.  */
-  void (*decode_location) (struct breakpoint *, char **,
-			   struct symtabs_and_lines *);
+  void (*decode_location) (struct breakpoint *b,
+			   const struct event_location *location,
+			   struct symtabs_and_lines *sals);
 
   /* Return true if this breakpoint explains a signal.  See
      bpstat_explains_signal.  */
@@ -702,17 +705,17 @@ struct breakpoint
        non-thread-specific ordinary breakpoints this is NULL.  */
     struct program_space *pspace;
 
-    /* String we used to set the breakpoint (malloc'd).  */
-    char *addr_string;
+    /* Location we used to set the breakpoint (malloc'd).  */
+    struct event_location *location;
 
     /* The filter that should be passed to decode_line_full when
        re-setting this breakpoint.  This may be NULL, but otherwise is
        allocated with xmalloc.  */
     char *filter;
 
-    /* For a ranged breakpoint, the string we used to find
+    /* For a ranged breakpoint, the location we used to find
        the end of the range (malloc'd).  */
-    char *addr_string_range_end;
+    struct event_location *location_range_end;
 
     /* Architecture we used to set the breakpoint.  */
     struct gdbarch *gdbarch;
@@ -1293,10 +1296,30 @@ enum breakpoint_create_flags
     CREATE_BREAKPOINT_FLAGS_INSERTED = 1 << 0
   };
 
-extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
+/* Set a breakpoint.  This function is shared between CLI and MI functions
+   for setting a breakpoint at LOCATION.
+
+   This function has two major modes of operations, selected by the
+   PARSE_EXTRA parameter.
+
+   If PARSE_EXTRA is zero, LOCATION is just the breakpoint's location,
+   with condition, thread, and extra string specified by the COND_STRING,
+   THREAD, and EXTRA_STRING parameters.
+
+   If PARSE_EXTRA is non-zero, this function will attempt to extract
+   the condition, thread, and extra string from EXTRA_STRING, ignoring
+   the similarly named parameters.
+
+   If INTERNAL is non-zero, the breakpoint number will be allocated
+   from the internal breakpoint count.
+
+   Returns true if any breakpoint was created; false otherwise.  */
+
+extern int create_breakpoint (struct gdbarch *gdbarch,
+			      const struct event_location *location,
 			      char *cond_string, int thread,
 			      char *extra_string,
-			      int parse_arg,
+			      int parse_extra,
 			      int tempflag, enum bptype wanted_type,
 			      int ignore_count,
 			      enum auto_boolean pending_break_support,
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 2ec2dd3..e9664c9 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -38,6 +38,7 @@
 #include "disasm.h"
 #include "tracepoint.h"
 #include "filestuff.h"
+#include "location.h"
 
 #include "ui-out.h"
 
@@ -782,7 +783,6 @@ edit_command (char *arg, int from_tty)
   struct symtabs_and_lines sals;
   struct symtab_and_line sal;
   struct symbol *sym;
-  char *arg1;
   char *editor;
   char *p;
   const char *fn;
@@ -804,21 +804,28 @@ edit_command (char *arg, int from_tty)
     }
   else
     {
-      /* Now should only be one argument -- decode it in SAL.  */
+      struct cleanup *cleanup;
+      struct event_location *location;
+      char *arg1;
 
+      /* Now should only be one argument -- decode it in SAL.  */
       arg1 = arg;
-      sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
+      location = string_to_event_location (&arg1, current_language);
+      cleanup = make_cleanup_delete_event_location (location);
+      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
 
       filter_sals (&sals);
       if (! sals.nelts)
 	{
 	  /*  C++  */
+	  do_cleanups (cleanup);
 	  return;
 	}
       if (sals.nelts > 1)
 	{
 	  ambiguous_line_spec (&sals);
 	  xfree (sals.sals);
+	  do_cleanups (cleanup);
 	  return;
 	}
 
@@ -860,6 +867,7 @@ edit_command (char *arg, int from_tty)
 
       if (sal.symtab == 0)
         error (_("No line number known for %s."), arg);
+      do_cleanups (cleanup);
     }
 
   if ((editor = (char *) getenv ("EDITOR")) == NULL)
@@ -888,6 +896,9 @@ list_command (char *arg, int from_tty)
   int dummy_beg = 0;
   int linenum_beg = 0;
   char *p;
+  struct cleanup *cleanup;
+
+  cleanup = make_cleanup (null_cleanup, NULL);
 
   /* Pull in the current default source line if necessary.  */
   if (arg == 0 || arg[0] == '+' || arg[0] == '-')
@@ -951,15 +962,24 @@ list_command (char *arg, int from_tty)
     dummy_beg = 1;
   else
     {
-      sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
+      struct event_location *location;
+
+      location = string_to_event_location (&arg1, current_language);
+      make_cleanup_delete_event_location (location);
+      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
 
       filter_sals (&sals);
       if (!sals.nelts)
-	return;			/*  C++  */
+	{
+	  /*  C++  */
+	  do_cleanups (cleanup);
+	  return;
+	}
       if (sals.nelts > 1)
 	{
 	  ambiguous_line_spec (&sals);
 	  xfree (sals.sals);
+	  do_cleanups (cleanup);
 	  return;
 	}
 
@@ -984,18 +1004,28 @@ list_command (char *arg, int from_tty)
 	dummy_end = 1;
       else
 	{
+	  struct event_location *location;
+
+	  location = string_to_event_location (&arg1, current_language);
+	  make_cleanup_delete_event_location (location);
 	  if (dummy_beg)
-	    sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
+	    sals_end = decode_line_1 (location,
+				      DECODE_LINE_LIST_MODE, 0, 0);
 	  else
-	    sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE,
+	    sals_end = decode_line_1 (location, DECODE_LINE_LIST_MODE,
 				      sal.symtab, sal.line);
+
 	  filter_sals (&sals_end);
 	  if (sals_end.nelts == 0)
-	    return;
+	    {
+	      do_cleanups (cleanup);
+	      return;
+	    }
 	  if (sals_end.nelts > 1)
 	    {
 	      ambiguous_line_spec (&sals_end);
 	      xfree (sals_end.sals);
+	      do_cleanups (cleanup);
 	      return;
 	    }
 	  sal_end = sals_end.sals[0];
@@ -1076,6 +1106,7 @@ list_command (char *arg, int from_tty)
 			 ? sal.line + get_lines_to_list ()
 			 : sal_end.line + 1),
 			0);
+  do_cleanups (cleanup);
 }
 
 /* Subroutine of disassemble_command to simplify it.
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 4b97b04..acf5112 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -45,6 +45,7 @@
 #include "bcache.h"
 #include "gdb_bfd.h"
 #include "build-id.h"
+#include "location.h"
 
 extern void _initialize_elfread (void);
 
@@ -1077,7 +1078,8 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
   resolved_pc = gdbarch_addr_bits_remove (gdbarch, resolved_pc);
 
   gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
-  elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
+  elf_gnu_ifunc_record_cache (event_location_to_string (b->location),
+			      resolved_pc);
 
   sal = find_pc_line (resolved_pc, 0);
   sals.nelts = 1;
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index ad853ed..b46f67d 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -31,6 +31,7 @@
 #include "arch-utils.h"
 #include "language.h"
 #include "guile-internal.h"
+#include "location.h"
 
 /* The <gdb:breakpoint> smob.
    N.B.: The name of this struct is known to breakpoint.h.
@@ -173,6 +174,8 @@ bpscm_print_breakpoint_smob (SCM self, SCM port, scm_print_state *pstate)
   /* Careful, the breakpoint may be invalid.  */
   if (b != NULL)
     {
+      const char *str;
+
       gdbscm_printf (port, " %s %s %s",
 		     bpscm_type_to_string (b->type),
 		     bpscm_enable_state_to_string (b->enable_state),
@@ -181,8 +184,9 @@ bpscm_print_breakpoint_smob (SCM self, SCM port, scm_print_state *pstate)
       gdbscm_printf (port, " hit:%d", b->hit_count);
       gdbscm_printf (port, " ignore:%d", b->ignore_count);
 
-      if (b->addr_string != NULL)
-	gdbscm_printf (port, " @%s", b->addr_string);
+      str = event_location_to_string (b->location);
+      if (str != NULL)
+	gdbscm_printf (port, " @%s", str);
     }
 
   scm_puts (">", port);
@@ -408,6 +412,9 @@ gdbscm_register_breakpoint_x (SCM self)
   breakpoint_smob *bp_smob
     = bpscm_get_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct gdb_exception except = exception_none;
+  char *location, *copy;
+  struct event_location *eloc;
+  struct cleanup *cleanup;
 
   /* We only support registering breakpoints created with make-breakpoint.  */
   if (!bp_smob->is_scheme_bkpt)
@@ -417,10 +424,13 @@ gdbscm_register_breakpoint_x (SCM self)
     scm_misc_error (FUNC_NAME, _("breakpoint is already registered"), SCM_EOL);
 
   pending_breakpoint_scm = self;
+  location = bp_smob->spec.location;
+  copy = location;
+  eloc = new_linespec_location (&copy);
+  cleanup = make_cleanup_delete_event_location (eloc);
 
   TRY
     {
-      char *location = bp_smob->spec.location;
       int internal = bp_smob->spec.is_internal;
 
       switch (bp_smob->spec.type)
@@ -428,7 +438,7 @@ gdbscm_register_breakpoint_x (SCM self)
 	case bp_breakpoint:
 	  {
 	    create_breakpoint (get_current_arch (),
-			       location, NULL, -1, NULL,
+			       eloc, NULL, -1, NULL,
 			       0,
 			       0, bp_breakpoint,
 			       0,
@@ -464,6 +474,7 @@ gdbscm_register_breakpoint_x (SCM self)
   /* Ensure this gets reset, even if there's an error.  */
   pending_breakpoint_scm = SCM_BOOL_F;
   GDBSCM_HANDLE_GDB_EXCEPTION (except);
+  do_cleanups (cleanup);
 
   return SCM_UNSPECIFIED;
 }
@@ -819,12 +830,12 @@ gdbscm_breakpoint_location (SCM self)
 {
   breakpoint_smob *bp_smob
     = bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
-  char *str;
+  const char *str;
 
   if (bp_smob->bp->type != bp_breakpoint)
     return SCM_BOOL_F;
 
-  str = bp_smob->bp->addr_string;
+  str = event_location_to_string (bp_smob->bp->location);
   if (! str)
     str = "";
 
diff --git a/gdb/linespec.c b/gdb/linespec.c
index a480be1..5949594 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -43,6 +43,7 @@
 #include "filenames.h"
 #include "ada-lang.h"
 #include "stack.h"
+#include "location.h"
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -281,8 +282,8 @@ struct ls_parser
     const char *saved_arg;
 
     /* Head of the input stream.  */
-    const char **stream;
-#define PARSER_STREAM(P) (*(P)->lexer.stream)
+    const char *stream;
+#define PARSER_STREAM(P) ((P)->lexer.stream)
 
     /* The current token.  */
     linespec_token current;
@@ -315,7 +316,7 @@ static CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
 
 static struct symtabs_and_lines decode_objc (struct linespec_state *self,
 					     linespec_p ls,
-					     const char **argptr);
+					     const char *arg);
 
 static VEC (symtab_ptr) *symtabs_from_filename (const char *);
 
@@ -1785,21 +1786,29 @@ linespec_parse_basic (linespec_parser *parser)
    STATE->canonical.  */
 
 static void
-canonicalize_linespec (struct linespec_state *state, linespec_p ls)
+canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 {
+  char *tmp;
+
   /* If canonicalization was not requested, no need to do anything.  */
   if (!state->canonical)
     return;
 
   /* Shortcut expressions, which can only appear by themselves.  */
   if (ls->expression != NULL)
-    state->canonical->addr_string = xstrdup (ls->expression);
+    {
+      tmp = ASTRDUP (ls->expression);
+      state->canonical->location = new_linespec_location (&tmp);
+    }
   else
     {
       struct ui_file *buf;
       int need_colon = 0;
+      struct cleanup *cleanup;
 
       buf = mem_fileopen ();
+      cleanup = make_cleanup_ui_file_delete (buf);
+
       if (ls->source_filename)
 	{
 	  fputs_unfiltered (ls->source_filename, buf);
@@ -1848,8 +1857,10 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 			    ls->line_offset.offset);
 	}
 
-      state->canonical->addr_string = ui_file_xstrdup (buf, NULL);
-      ui_file_delete (buf);
+      tmp = ui_file_xstrdup (buf, NULL);
+      make_cleanup (xfree, tmp);
+      state->canonical->location = new_linespec_location (&tmp);
+      do_cleanups (cleanup);
     }
 }
 
@@ -2117,8 +2128,6 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 }
 
 /* Parse a string that specifies a linespec.
-   Pass the address of a char * variable; that variable will be
-   advanced over the characters actually parsed.
 
    The basic grammar of linespecs:
 
@@ -2167,10 +2176,10 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
    if no file is validly specified.  Callers must check that.
    Also, the line number returned may be invalid.  */
 
-/* Parse the linespec in ARGPTR.  */
+/* Parse the linespec in ARG.  */
 
 static struct symtabs_and_lines
-parse_linespec (linespec_parser *parser, const char **argptr)
+parse_linespec (linespec_parser *parser, const char *arg)
 {
   linespec_token token;
   struct symtabs_and_lines values;
@@ -2181,30 +2190,30 @@ parse_linespec (linespec_parser *parser, const char **argptr)
      IDEs to work around bugs in the previous parser by quoting
      the entire linespec, so we attempt to deal with this nicely.  */
   parser->is_quote_enclosed = 0;
-  if (!is_ada_operator (*argptr)
-      && strchr (linespec_quote_characters, **argptr) != NULL)
+  if (!is_ada_operator (arg)
+      && strchr (linespec_quote_characters, *arg) != NULL)
     {
       const char *end;
 
-      end = skip_quote_char (*argptr + 1, **argptr);
+      end = skip_quote_char (arg + 1, *arg);
       if (end != NULL && is_closing_quote_enclosed (end))
 	{
-	  /* Here's the special case.  Skip ARGPTR past the initial
+	  /* Here's the special case.  Skip ARG past the initial
 	     quote.  */
-	  ++(*argptr);
+	  ++arg;
 	  parser->is_quote_enclosed = 1;
 	}
     }
 
-  parser->lexer.saved_arg = *argptr;
-  parser->lexer.stream = argptr;
+  parser->lexer.saved_arg = arg;
+  parser->lexer.stream = arg;
 
   /* Initialize the default symtab and line offset.  */
   initialize_defaults (&PARSER_STATE (parser)->default_symtab,
 		       &PARSER_STATE (parser)->default_line);
 
   /* Objective-C shortcut.  */
-  values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), argptr);
+  values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg);
   if (values.sals != NULL)
     return values;
 
@@ -2390,6 +2399,7 @@ linespec_parser_new (linespec_parser *parser,
 		     int default_line,
 		     struct linespec_result *canonical)
 {
+  memset (parser, 0, sizeof (linespec_parser));
   parser->lexer.current.type = LSTOKEN_CONSUMED;
   memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
   PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
@@ -2443,7 +2453,6 @@ linespec_lex_to_end (char **stringp)
   linespec_parser parser;
   struct cleanup *cleanup;
   linespec_token token;
-  volatile struct gdb_exception e;
   const char *orig;
 
   if (stringp == NULL || *stringp == NULL)
@@ -2490,10 +2499,42 @@ linespec_lex_to_end (char **stringp)
   do_cleanups (cleanup);
 }
 
+/* A helper function for decode_line_full and decode_line_1 to
+   turn LOCATION into symtabs_and_lines.  */
+
+static struct symtabs_and_lines
+event_location_to_sals (linespec_parser *parser,
+			const struct event_location *location)
+{
+  struct symtabs_and_lines result = {NULL, 0};
+
+  switch (event_location_type (location))
+    {
+    case LINESPEC_LOCATION:
+      {
+	TRY
+	  {
+	    result = parse_linespec (parser, get_linespec_location (location));
+	  }
+	CATCH (except, RETURN_MASK_ERROR)
+	  {
+	    throw_exception (except);
+	  }
+	END_CATCH
+      }
+      break;
+
+    default:
+      gdb_assert_not_reached ("unhandled event location type");
+    }
+
+  return result;
+}
+
 /* See linespec.h.  */
 
 void
-decode_line_full (char **argptr, int flags,
+decode_line_full (const struct event_location *location, int flags,
 		  struct symtab *default_symtab,
 		  int default_line, struct linespec_result *canonical,
 		  const char *select_mode,
@@ -2504,7 +2545,6 @@ decode_line_full (char **argptr, int flags,
   VEC (const_char_ptr) *filters = NULL;
   linespec_parser parser;
   struct linespec_state *state;
-  const char *copy, *orig;
 
   gdb_assert (canonical != NULL);
   /* The filter only makes sense for 'all'.  */
@@ -2520,13 +2560,10 @@ decode_line_full (char **argptr, int flags,
   cleanups = make_cleanup (linespec_parser_delete, &parser);
   save_current_program_space ();
 
-  orig = copy = *argptr;
-  result = parse_linespec (&parser, &copy);
-  *argptr += copy - orig;
+  result = event_location_to_sals (&parser, location);
   state = PARSER_STATE (&parser);
 
   gdb_assert (result.nelts == 1 || canonical->pre_expanded);
-  gdb_assert (canonical->addr_string != NULL);
   canonical->pre_expanded = 1;
 
   /* Arrange for allocated canonical names to be freed.  */
@@ -2570,23 +2607,20 @@ decode_line_full (char **argptr, int flags,
 /* See linespec.h.  */
 
 struct symtabs_and_lines
-decode_line_1 (char **argptr, int flags,
+decode_line_1 (const struct event_location *location, int flags,
 	       struct symtab *default_symtab,
 	       int default_line)
 {
   struct symtabs_and_lines result;
   linespec_parser parser;
   struct cleanup *cleanups;
-  const char *copy, *orig;
 
   linespec_parser_new (&parser, flags, current_language, default_symtab,
 		       default_line, NULL);
   cleanups = make_cleanup (linespec_parser_delete, &parser);
   save_current_program_space ();
 
-  orig = copy = *argptr;
-  result = parse_linespec (&parser, &copy);
-  *argptr += copy - orig;
+  result = event_location_to_sals (&parser, location);
 
   do_cleanups (cleanups);
   return result;
@@ -2599,6 +2633,8 @@ decode_line_with_current_source (char *string, int flags)
 {
   struct symtabs_and_lines sals;
   struct symtab_and_line cursal;
+  struct event_location *location;
+  struct cleanup *cleanup;
 
   if (string == 0)
     error (_("Empty line specification."));
@@ -2607,11 +2643,15 @@ decode_line_with_current_source (char *string, int flags)
      and get a default source symtab+line or it will recursively call us!  */
   cursal = get_current_source_symtab_and_line ();
 
-  sals = decode_line_1 (&string, flags,
+  location = string_to_event_location (&string, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
+  sals = decode_line_1 (location, flags,
 			cursal.symtab, cursal.line);
 
   if (*string)
     error (_("Junk at end of line specification: %s"), string);
+
+  do_cleanups (cleanup);
   return sals;
 }
 
@@ -2621,19 +2661,25 @@ struct symtabs_and_lines
 decode_line_with_last_displayed (char *string, int flags)
 {
   struct symtabs_and_lines sals;
+  struct event_location *location;
+  struct cleanup *cleanup;
 
   if (string == 0)
     error (_("Empty line specification."));
 
+  location = string_to_event_location (&string, current_language);
+  cleanup = make_cleanup_delete_event_location (location);
   if (last_displayed_sal_is_valid ())
-    sals = decode_line_1 (&string, flags,
+    sals = decode_line_1 (location, flags,
 			  get_last_displayed_symtab (),
 			  get_last_displayed_line ());
   else
-    sals = decode_line_1 (&string, flags, (struct symtab *) NULL, 0);
+    sals = decode_line_1 (location, flags, (struct symtab *) NULL, 0);
 
   if (*string)
     error (_("Junk at end of line specification: %s"), string);
+
+  do_cleanups (cleanup);
   return sals;
 }
 
@@ -2686,7 +2732,7 @@ linespec_expression_to_pc (const char **exp_ptr)
    the existing C++ code to let the user choose one.  */
 
 static struct symtabs_and_lines
-decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
+decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
 {
   struct collect_info info;
   VEC (const_char_ptr) *symbol_names = NULL;
@@ -2704,7 +2750,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
   values.nelts = 0;
   values.sals = NULL;
 
-  new_argptr = find_imps (*argptr, &symbol_names); 
+  new_argptr = find_imps (arg, &symbol_names);
   if (VEC_empty (const_char_ptr, symbol_names))
     {
       do_cleanups (cleanup);
@@ -2718,9 +2764,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
     {
       char *saved_arg;
 
-      saved_arg = alloca (new_argptr - *argptr + 1);
-      memcpy (saved_arg, *argptr, new_argptr - *argptr);
-      saved_arg[new_argptr - *argptr] = '\0';
+      saved_arg = alloca (new_argptr - arg + 1);
+      memcpy (saved_arg, arg, new_argptr - arg);
+      saved_arg[new_argptr - arg] = '\0';
 
       ls->function_name = xstrdup (saved_arg);
       ls->function_symbols = info.result.symbols;
@@ -2729,17 +2775,23 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
 
       if (self->canonical)
 	{
+	  char *str;
+
 	  self->canonical->pre_expanded = 1;
+
 	  if (ls->source_filename)
-	    self->canonical->addr_string
-	      = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
+	    {
+	      str = xstrprintf ("%s:%s",
+				ls->source_filename, saved_arg);
+	    }
 	  else
-	    self->canonical->addr_string = xstrdup (saved_arg);
+	    str = xstrdup (saved_arg);
+
+	  make_cleanup (xfree, str);
+	  self->canonical->location = new_linespec_location (&str);
 	}
     }
 
-  *argptr = new_argptr;
-
   do_cleanups (cleanup);
 
   return values;
@@ -3819,7 +3871,7 @@ destroy_linespec_result (struct linespec_result *ls)
   int i;
   struct linespec_sals *lsal;
 
-  xfree (ls->addr_string);
+  delete_event_location (ls->location);
   for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
     {
       xfree (lsal->canonical);
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 77ec46d..840bae5 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -39,7 +39,7 @@ enum decode_line_flags
 
 struct linespec_sals
 {
-  /* This is the linespec corresponding to the sals contained in this
+  /* This is the location corresponding to the sals contained in this
      object.  It can be passed as the FILTER argument to future calls
      to decode_line_full.  This is freed by
      destroy_linespec_result.  */
@@ -71,9 +71,9 @@ struct linespec_result
      object.  */
   int pre_expanded;
 
-  /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+  /* If PRE_EXPANDED is non-zero, this is set to the location entered
      by the user.  This will be freed by destroy_linespec_result.  */
-  char *addr_string;
+  struct event_location *location;
 
   /* The sals.  The vector will be freed by
      destroy_linespec_result.  */
@@ -96,10 +96,10 @@ extern struct cleanup *
 /* Decode a linespec using the provided default symtab and line.  */
 
 extern struct symtabs_and_lines
-	decode_line_1 (char **argptr, int flags,
+	decode_line_1 (const struct event_location *location, int flags,
 		       struct symtab *default_symtab, int default_line);
 
-/* Parse *ARGPTR as a linespec and return results.  This is the "full"
+/* Parse LOCATION and return results.  This is the "full"
    interface to this module, which handles multiple results
    properly.
 
@@ -135,7 +135,7 @@ extern struct symtabs_and_lines
    strcmp sense) to FILTER will be returned; all others will be
    filtered out.  */
 
-extern void decode_line_full (char **argptr, int flags,
+extern void decode_line_full (const struct event_location *location, int flags,
 			      struct symtab *default_symtab, int default_line,
 			      struct linespec_result *canonical,
 			      const char *select_mode,
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 186f807..c8c988d 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -28,6 +28,9 @@
 #include "observer.h"
 #include "mi-main.h"
 #include "mi-cmd-break.h"
+#include "language.h"
+#include "location.h"
+#include "linespec.h"
 #include "gdb_obstack.h"
 #include <ctype.h>
 
@@ -177,6 +180,7 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
   int tracepoint = 0;
   struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
   enum bptype type_wanted;
+  struct event_location *location;
   struct breakpoint_ops *ops;
   char *extra_string = NULL;
 
@@ -287,7 +291,13 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
       ops = &bkpt_breakpoint_ops;
     }
 
-  create_breakpoint (get_current_arch (), address, condition, thread,
+  location = string_to_event_location (&address, current_language);
+  make_cleanup_delete_event_location (location);
+
+  if (*address)
+    error (_("Garbage '%s' at end of location"), address);
+
+  create_breakpoint (get_current_arch (), location, condition, thread,
 		     extra_string,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,
diff --git a/gdb/probe.c b/gdb/probe.c
index dce2b25..8366220 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -33,6 +33,7 @@
 #include "value.h"
 #include "ax.h"
 #include "ax-gdb.h"
+#include "location.h"
 #include <ctype.h>
 
 typedef struct bound_probe bound_probe_s;
@@ -43,23 +44,24 @@ DEF_VEC_O (bound_probe_s);
 /* See definition in probe.h.  */
 
 struct symtabs_and_lines
-parse_probes (char **argptr, struct linespec_result *canonical)
+parse_probes (const struct event_location *location,
+	      struct linespec_result *canonical)
 {
-  char *arg_start, *arg_end, *arg;
+  char *arg_end, *arg;
   char *objfile_namestr = 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 = *argptr;
+  arg_start = get_linespec_location (location);
 
-  cs = *argptr;
+  cs = arg_start;
   probe_ops = probe_linespec_to_ops (&cs);
   if (probe_ops == NULL)
     error (_("'%s' is not a probe linespec"), arg_start);
@@ -170,12 +172,15 @@ parse_probes (char **argptr, struct linespec_result *canonical)
 
   if (canonical)
     {
+      char *canon;
+
+      canon = savestring (arg_start, arg_end - arg_start);
+      make_cleanup (xfree, canon);
       canonical->special_display = 1;
       canonical->pre_expanded = 1;
-      canonical->addr_string = savestring (*argptr, arg_end - *argptr);
+      canonical->location = new_linespec_location (&canon);
     }
 
-  *argptr = arg_end;
   do_cleanups (cleanup);
 
   return result;
diff --git a/gdb/probe.h b/gdb/probe.h
index e8d5dfe..c058a38 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -20,6 +20,8 @@
 #if !defined (PROBE_H)
 #define PROBE_H 1
 
+struct event_location;
+
 #include "gdb_vecs.h"
 
 /* Definition of a vector of probes.  */
@@ -219,9 +221,9 @@ struct bound_probe
   };
 
 /* A helper for linespec that decodes a probe specification.  It returns a
-   symtabs_and_lines object and updates *ARGPTR or throws an error.  */
+   symtabs_and_lines object and updates LOC or throws an error.  */
 
-extern struct symtabs_and_lines parse_probes (char **argptr,
+extern struct symtabs_and_lines parse_probes (const struct event_location *loc,
 					      struct linespec_result *canon);
 
 /* Helper function to register the proper probe_ops to a newly created probe.
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 42a8596..30619dc 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -30,6 +30,7 @@
 #include "ada-lang.h"
 #include "arch-utils.h"
 #include "language.h"
+#include "location.h"
 
 /* Number of live breakpoints.  */
 static int bppy_live;
@@ -380,7 +381,7 @@ bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
 static PyObject *
 bppy_get_location (PyObject *self, void *closure)
 {
-  char *str;
+  const char *str;
   gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
 
   BPPY_REQUIRE_VALID (obj);
@@ -388,8 +389,7 @@ bppy_get_location (PyObject *self, void *closure)
   if (obj->bp->type != bp_breakpoint)
     Py_RETURN_NONE;
 
-  str = obj->bp->addr_string;
-
+  str = event_location_to_string (obj->bp->location);
   if (! str)
     str = "";
   return PyString_Decode (str, strlen (str), host_charset (), NULL);
@@ -670,8 +670,12 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 	{
 	case bp_breakpoint:
 	  {
+	    struct event_location *location;
+
+	    location = new_linespec_location (&copy);
+	    make_cleanup_delete_event_location (location);
 	    create_breakpoint (python_gdbarch,
-			       copy, NULL, -1, NULL,
+			       location, NULL, -1, NULL,
 			       0,
 			       temporary_bp, bp_breakpoint,
 			       0,
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index 34e9643..2160ef5 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -29,6 +29,7 @@
 #include "observer.h"
 #include "inferior.h"
 #include "block.h"
+#include "location.h"
 
 /* Function that is called when a Python finish bp is found out of scope.  */
 static char * const outofscope_func = "out_of_scope";
@@ -166,7 +167,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
   PyObject *internal = NULL;
   int internal_bp = 0;
   CORE_ADDR finish_pc, pc;
-  char *addr_str, small_buf[100];
+  char small_buf[100], *p;
   struct symbol *function;
 
   if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
@@ -293,13 +294,17 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 
   TRY
     {
+      struct event_location *location;
+      struct cleanup *back_to;
+
       /* Set a breakpoint on the return address.  */
       finish_pc = get_frame_pc (prev_frame);
       xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc));
-      addr_str = small_buf;
-
+      p = small_buf;
+      location = new_linespec_location (&p);
+      back_to = make_cleanup_delete_event_location (location);
       create_breakpoint (python_gdbarch,
-                         addr_str, NULL, thread, NULL,
+                         location, NULL, thread, NULL,
                          0,
                          1 /*temp_flag*/,
                          bp_breakpoint,
@@ -307,6 +312,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                          AUTO_BOOLEAN_TRUE,
                          &bkpt_breakpoint_ops,
                          0, 1, internal_bp, 0);
+      do_cleanups (back_to);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 4f88b0e..c28f98b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -34,6 +34,7 @@
 #include "extension-priv.h"
 #include "cli/cli-utils.h"
 #include <ctype.h>
+#include "location.h"
 
 /* Declared constants and enum for python stack printing.  */
 static const char python_excp_none[] = "none";
@@ -724,12 +725,12 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
   struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to
 						  appease gcc.  */
   struct symtab_and_line sal;
-  const char *arg = NULL;
-  char *copy_to_free = NULL, *copy = NULL;
+  char *arg = NULL;
   struct cleanup *cleanups;
   PyObject *result = NULL;
   PyObject *return_result = NULL;
   PyObject *unparsed = NULL;
+  struct event_location *location;
 
   if (! PyArg_ParseTuple (args, "|s", &arg))
     return NULL;
@@ -738,14 +739,16 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
 
   sals.sals = NULL;
 
+  if (arg != NULL)
+    {
+      location = new_linespec_location (&arg);
+      make_cleanup_delete_event_location (location);
+    }
+
   TRY
     {
       if (arg)
-	{
-	  copy = xstrdup (arg);
-	  copy_to_free = copy;
-	  sals = decode_line_1 (&copy, 0, 0, 0);
-	}
+	sals = decode_line_1 (location, 0, 0, 0);
       else
 	{
 	  set_default_source_symtab_and_line ();
@@ -761,10 +764,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
   END_CATCH
 
   if (sals.sals != NULL && sals.sals != &sal)
-    {
-      make_cleanup (xfree, copy_to_free);
-      make_cleanup (xfree, sals.sals);
-    }
+    make_cleanup (xfree, sals.sals);
 
   if (except.reason < 0)
     {
@@ -808,9 +808,9 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
       goto error;
     }
 
-  if (copy && strlen (copy) > 0)
+  if (arg != NULL && strlen (arg) > 0)
     {
-      unparsed = PyString_FromString (copy);
+      unparsed = PyString_FromString (arg);
       if (unparsed == NULL)
 	{
 	  Py_DECREF (result);
diff --git a/gdb/remote.c b/gdb/remote.c
index 3b2325f..65536e8 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -44,6 +44,7 @@
 #include "gdb_bfd.h"
 #include "filestuff.h"
 #include "rsp-low.h"
+#include "location.h"
 
 #include <sys/time.h>
 
@@ -10729,13 +10730,12 @@ remote_download_tracepoint (struct target_ops *self, struct bp_location *loc)
 
   if (packet_support (PACKET_TracepointSource) == PACKET_ENABLE)
     {
-      if (b->addr_string)
+      if (b->location != NULL)
 	{
 	  strcpy (buf, "QTDPsrc:");
-	  encode_source_string (b->number, loc->address,
-				"at", b->addr_string, buf + strlen (buf),
-				2048 - strlen (buf));
-
+	  encode_source_string (b->number, loc->address, "at",
+				event_location_to_string (b->location),
+				buf + strlen (buf), 2048 - strlen (buf));
 	  putpkt (buf);
 	  remote_get_noisy_reply (&target_buf, &target_buf_size);
 	  if (strcmp (target_buf, "OK"))
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 7e05834..83f4c6e 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -45,7 +45,7 @@
 #include "dwarf2-frame.h"
 #include "ax.h"
 #include "spu-tdep.h"
-
+#include "location.h"
 
 /* The list of available "set spu " and "show spu " commands.  */
 static struct cmd_list_element *setspucmdlist = NULL;
@@ -1954,8 +1954,10 @@ spu_catch_start (struct objfile *objfile)
 {
   struct bound_minimal_symbol minsym;
   struct compunit_symtab *cust;
+  char buf[32], *p;
   CORE_ADDR pc;
-  char buf[32];
+  struct event_location *location;
+  struct cleanup *back_to;
 
   /* Do this only if requested by "set spu stop-on-load on".  */
   if (!spu_stop_on_load_p)
@@ -2000,7 +2002,10 @@ spu_catch_start (struct objfile *objfile)
   /* Use a numerical address for the set_breakpoint command to avoid having
      the breakpoint re-set incorrectly.  */
   xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
-  create_breakpoint (get_objfile_arch (objfile), buf /* arg */,
+  p = buf;
+  location = new_linespec_location (&p);
+  back_to = make_cleanup_delete_event_location (location);
+  create_breakpoint (get_objfile_arch (objfile), location,
 		     NULL /* cond_string */, -1 /* thread */,
 		     NULL /* extra_string */,
 		     0 /* parse_condition_and_thread */, 1 /* tempflag */,
@@ -2009,6 +2014,7 @@ spu_catch_start (struct objfile *objfile)
 		     AUTO_BOOLEAN_FALSE /* pending_break_support */,
 		     &bkpt_breakpoint_ops /* ops */, 0 /* from_tty */,
 		     1 /* enabled */, 0 /* internal  */, 0);
+  do_cleanups (back_to);
 }
 
 
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7c04ecb..af553a3 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -55,6 +55,7 @@
 #include "filestuff.h"
 #include "rsp-low.h"
 #include "tracefile.h"
+#include "location.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -2712,14 +2713,22 @@ scope_info (char *args, int from_tty)
   int j, count = 0;
   struct gdbarch *gdbarch;
   int regno;
+  struct event_location *location;
+  struct cleanup *back_to;
 
   if (args == 0 || *args == 0)
     error (_("requires an argument (function, "
 	     "line or *addr) to define a scope"));
 
-  sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
+  location = string_to_event_location (&args, current_language);
+  back_to = make_cleanup_delete_event_location (location);
+  sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
   if (sals.nelts == 0)
-    return;		/* Presumably decode_line_1 has already warned.  */
+    {
+      /* Presumably decode_line_1 has already warned.  */
+      do_cleanups (back_to);
+      return;
+    }
 
   /* Resolve line numbers to PC.  */
   resolve_sal_pc (&sals.sals[0]);
@@ -2856,6 +2865,7 @@ scope_info (char *args, int from_tty)
   if (count <= 0)
     printf_filtered ("Scope for %s contains no locals or arguments.\n",
 		     save_args);
+  do_cleanups (back_to);
 }
 
 /* Helper for trace_dump_command.  Dump the action list starting at
@@ -3078,7 +3088,7 @@ trace_dump_command (char *args, int from_tty)
 
 extern int
 encode_source_string (int tpnum, ULONGEST addr,
-		      char *srctype, char *src, char *buf, int buf_size)
+		      char *srctype, const char *src, char *buf, int buf_size)
 {
   if (80 + strlen (srctype) > buf_size)
     error (_("Buffer too small for source encoding"));
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index f34be15..549cf61 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -298,7 +298,7 @@ extern struct trace_state_variable *
 extern struct trace_state_variable *create_trace_state_variable (const char *name);
 
 extern int encode_source_string (int num, ULONGEST addr,
-				 char *srctype, char *src,
+				 char *srctype, const char *src,
 				 char *buf, int buf_size);
 
 extern void parse_trace_status (char *line, struct trace_status *ts);

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 8/9] Explicit locations: MI support for explicit locations
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
  2015-05-07 18:05 ` [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
  2015-05-07 18:06 ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  7:16   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 7/9] Explicit locations: add UI features for CLI Keith Seitz
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch adds support for explicit locations to MI's -break-insert
command. The new options, documented in the User Manual, are
--source, --line, --function, and --label.

gdb/ChangeLog:

	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Add support for
	explicit locations, options "--source", "--function",
	"--label", and "--line".

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-break.exp (test_explicit_breakpoints): New proc.
	(at toplevel): Call test_explicit_breakpoints.
	* gdb.mi/mi-dprintf.exp: Add tests for explicit dprintf
	breakpoints.
	* lib/mi-support.exp (mi_make_breakpoint): Add support for
	breakpoint conditions, "-cond".
---
 gdb/mi/mi-cmd-break.c               |   72 +++++++++++++++++++++++++++----
 gdb/testsuite/gdb.mi/mi-break.exp   |   82 +++++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.mi/mi-dprintf.exp |   12 +++++
 gdb/testsuite/lib/mi-support.exp    |   16 ++++++-
 4 files changed, 169 insertions(+), 13 deletions(-)

diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index c8c988d..4aded13 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -182,6 +182,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
@@ -189,6 +191,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[] =
   {
@@ -200,6 +204,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},
+    {"-source" , EXPLICIT_SOURCE_OPT, 1},
+    {"-function", EXPLICIT_FUNC_OPT, 1},
+    {"-label", EXPLICIT_LABEL_OPT, 1},
+    {"-line", EXPLICIT_LINE_OPT, 1},
     { 0, 0, 0 }
   };
 
@@ -208,6 +216,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,
@@ -240,16 +250,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"));
@@ -258,11 +283,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!  */
@@ -291,11 +326,30 @@ 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);
-  make_cleanup_delete_event_location (location);
+  if (is_explicit)
+    {
+      /* Error check -- we must have one of the other
+	 parameters specified.  */
+      if (explicit.source_filename != NULL
+	  && explicit.function_name == NULL
+	  && explicit.label_name == NULL
+	  && explicit.line_offset.sign == LINE_OFFSET_UNKNOWN)
+	error (_("-%s-insert: --source option requires --function, --label,"
+		 " or --line"), dprintf ? "dprintf" : "break");
+
+      location = new_explicit_location (&explicit);
+    }
+  else
+    {
+      location = string_to_event_location (&address, current_language);
+      if (*address)
+	{
+	  delete_event_location (location);
+	  error (_("Garbage '%s' at end of location"), address);
+	}
+    }
 
-  if (*address)
-    error (_("Garbage '%s' at end of location"), address);
+  make_cleanup_delete_event_location (location);
 
   create_breakpoint (get_current_arch (), location, condition, thread,
 		     extra_string,
diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index a86ba8c..60bab0e 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -305,6 +305,86 @@ 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 srcfile
+    global line_callee3_head line_callee4_head
+    global line_callee2_body line_main_body
+
+    mi_delete_breakpoints
+
+    # First check mixed explicit/parsed linespecs.
+    mi_gdb_test "-break-insert --function 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 --function main
+    # -break-insert -t --source basics.c --function callee2
+    # -break-insert -t --source basics.c --line $line_callee3_head
+    # -break-insert -t --source srcfile --line $line_callee4_head
+    # -break-list
+
+    set bps {}
+    lappend bps [mi_create_breakpoint "-t --function main" \
+		     "insert temp explicit breakpoint in main" \
+		     -func main -file ".*$srcfile" -line $line_main_body]
+
+    lappend bps \
+	[mi_create_breakpoint "-t --source $srcfile --function callee2" \
+	     "insert temp explicit breakpoint at $srcfile:callee2" \
+	     -func callee2 -file ".*$srcfile" -line $line_callee2_body]
+
+    lappend bps \
+	[mi_create_breakpoint "-t --source $srcfile --line $line_callee3_head" \
+	     "insert temp explicit breakpoint at $srcfile:$line_callee3_head" \
+	     -func callee3 -file ".*$srcfile" -line $line_callee3_head]
+
+    lappend bps \
+	[mi_create_breakpoint \
+	     "-t --source \"$srcfile\" --line  $line_callee4_head" \
+	     "insert temp explicit breakpoint at \"$srcfile\":$line_callee4_head" \
+	     -func callee4 -file ".*$srcfile" -line $line_callee4_head]
+
+    mi_gdb_test "-break-list" "\\^done,[mi_make_breakpoint_table $bps]" \
+	"list of explicit breakpoints"
+
+    mi_gdb_test "-break-delete" \
+	    "\\^done" \
+	    "delete temp breakpoints"
+
+    mi_create_breakpoint "-c \"intarg == 3\" --function callee2" \
+	"insert explicit conditional breakpoint in callee2" \
+	-func callee2 ".*$srcfile" -line $line_callee2_body \
+	-cond "intarg == 3"
+
+    # mi_create_breakpoint cannot deal with displaying canonical
+    # linespecs.
+    mi_gdb_test \
+	"-break-insert -c \"foo == 3\" --source $srcfile --function main --label label" \
+	".*No symbol \"foo\" in current context.*"
+
+    mi_gdb_test \
+	"-break-insert --source foobar.c --line 3" \
+	".*No source file named foobar.c.*"
+
+    mi_gdb_test \
+	"-break-insert --source $srcfile --function foobar" \
+	".*Function \"foobar\" not defined in \"$srcfile\".*"
+
+    mi_gdb_test \
+	"-break-insert --source $srcfile --function main --label foobar" \
+	".*No label \"foobar\" defined in function \"main\".*"
+
+    mi_gdb_test \
+	"-break-insert --source $srcfile" \
+	".*Source filename requires function, label, or line offset.*"
+}
+
 test_tbreak_creation_and_listing
 test_rbreak_creation_and_listing
 
@@ -318,5 +398,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 ea198bd..d4f8ab0 100644
--- a/gdb/testsuite/gdb.mi/mi-dprintf.exp
+++ b/gdb/testsuite/gdb.mi/mi-dprintf.exp
@@ -47,6 +47,16 @@ 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 "-dprintf-insert --function main \"hello\"" \
+    "\\^done,bkpt={.*}" "explicit dprintf at main"
+
+mi_gdb_test "-dprintf-insert --source $srcfile --line $dp_location1 \"hello\"" \
+    "\\^done,bkpt={.*}" "explicit breakpoint at $srcfile:$dp_location1"
+
+mi_gdb_test "-dprintf-insert --source $srcfile \"hello\"" \
+    "\\^error,msg=\"-dprintf-insert: --source option requires --function, --label, or --line\"" "invalid explicit dprintf"
+
 mi_delete_breakpoints
 
 set bps [mi_make_breakpoint -type dprintf -func foo -file ".*mi-dprintf.c" \
@@ -61,7 +71,7 @@ mi_gdb_test "[incr i]-dprintf-insert $dp_location1 \"arg=%d, g=%d\\n\" arg g" \
 		   "$i\\^done,$bps" "mi insert dprintf dp_location1"
 
 set bps {}
-lappend bps [mi_make_breakpoint -number 3 -type dprintf -func foo \
+lappend bps [mi_make_breakpoint -type dprintf -func foo \
 		 -file ".*mi-dprintf.c" -fullname ".*mi-dprintf.c"]
 lappend bps [mi_make_breakpoint -type dprintf -func foo \
 		 -file ".*mi-dprintf.c" -fullname ".*mi-dprintf.c" \
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 6827ef9..188d153 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -2409,7 +2409,7 @@ proc mi_build_kv_pairs {attr_list {joiner ,}} {
 #
 # All arguments for the breakpoint may be specified using the options
 # number, type, disp, enabled, addr, func, file, fullanme, line,
-# thread-groups, times, ignore, script, and original-location.
+# thread-groups, cond, times, ignore, script, and original-location.
 #
 # Only if -script and -ignore are given will they appear in the output.
 # Otherwise, this procedure will skip them using ".*".
@@ -2424,17 +2424,27 @@ proc mi_make_breakpoint {args} {
     parse_args {{number .*} {type .*} {disp .*} {enabled .*} {addr .*}
 	{func .*} {file .*} {fullname .*} {line .*}
 	{thread-groups \\\[.*\\\]} {times .*} {ignore 0}
-	{script ""} {original-location .*}}
+	{script ""} {original-location .*} {cond ""}}
 
     set attr_list {}
     foreach attr [list number type disp enabled addr func file \
-		      fullname line thread-groups times] {
+		      fullname line thread-groups] {
 	lappend attr_list $attr [set $attr]
     }
 
     set result "bkpt={[mi_build_kv_pairs $attr_list]"
 
     # There are always exceptions.
+
+    # If COND is not preset, do not output it.
+    if {[string length $cond] > 0} {
+	append result ","
+	append result [mi_build_kv_pairs [list "cond" $cond]]
+    }
+
+    append result ","
+    append result [mi_build_kv_pairs [list "times" ".*"]]
+
     # If SCRIPT and IGNORE are not present, do not output them.
     if {$ignore != 0} {
 	append result ","

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location"
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (5 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 4/9] Explicit locations: introduce address locations Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-17 20:10   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 3/9] Explicit locations: use new location API Keith Seitz
  2015-05-07 18:13 ` [PATCH v4 9/9] Explicit locations: documentation updates Keith Seitz
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch renames all occurrances of "addr_string" and "address
string" in the breakpoint/linespec APIs.  This will emphasize the
change from address strings used in setting breakpoints (et al) to the
new locations-based API introduced in subsequent patches.

gdb/ChangeLog:

	* breakpoint.h (struct breakpoint_ops) <create_sals_from_address>:
	Renamed to create_sals_from_location.
	<decode_linespec>: Renamed to decode_location.
	Update all callers.
	* breakpoint.c (create_sals_from_address_default): Renamed to ...
	(create_sals_from_location_default): ... this.
	(addr_string_to_sals): Renamed to ...
	(location_to_sals): ... this.
	(decode_linespec_default): Renamed to ...
	(decode_location_default): ... this.
	(base_breakpoint_create_sals_from_address): Renamed to ...
	(base_breakpoint_create_sals_from_location): ... this.
	(bkpt_create_sals_from_address): Renamed to ...
	(bkpt_create_sals_from_location): ... this.
	(bkpt_decode_linespec): Renamed to ...
	(bkpt_decode_location): ... this.
	(bkpt_probe_create_sals_from_address): Renamed to ...
	(bkpt_probe_create_sals_from_location): ... this.
	(tracepoint_create_sals_from_address): Renamed to ...
	(tracepoint_create_sals_from_location): ... this.
	(tracepoint_decode_linespec): Renamed to ...
	(tracepoint_decode_location): ... this.
	(tracepoint_probe_create_sals_from_address): Renamed to ...
	(tracepoint_probe_create_sals_from_location): ... this.
	(tracepoint_probe_decode_linespec): Renamed to ...
	(tracepoint_probe_decode_location): ... this.
	(strace_marker_create_sals_from_address): Renamed to ...
	(strace_marker_create_sals_from_location): ... this.
	(decode_linespec_default): Renamed to ...
	(decode_location_default): ... this.
---
 gdb/break-catch-throw.c |    2 -
 gdb/breakpoint.c        |  116 ++++++++++++++++++++++++-----------------------
 gdb/breakpoint.h        |   14 +++---
 3 files changed, 66 insertions(+), 66 deletions(-)

diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index f5616c8..927176f 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -228,7 +228,7 @@ re_set_exception_catchpoint (struct breakpoint *self)
 	{
 	  char *spec = ASTRDUP (exception_functions[kind].function);
 
-	  self->ops->decode_linespec (self, &spec, &sals);
+	  self->ops->decode_location (self, &spec, &sals);
 	}
       CATCH (ex, RETURN_MASK_ERROR)
 	{
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a3531a0..31b1f82 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -108,10 +108,10 @@ static int breakpoint_re_set_one (void *);
 
 static void breakpoint_re_set_default (struct breakpoint *);
 
-static void create_sals_from_address_default (char **,
-					      struct linespec_result *,
-					      enum bptype, char *,
-					      char **);
+static void create_sals_from_location_default (char **,
+					       struct linespec_result *,
+					       enum bptype, char *,
+					       char **);
 
 static void create_breakpoints_sal_default (struct gdbarch *,
 					    struct linespec_result *,
@@ -121,7 +121,7 @@ static void create_breakpoints_sal_default (struct gdbarch *,
 					    const struct breakpoint_ops *,
 					    int, int, int, unsigned);
 
-static void decode_linespec_default (struct breakpoint *, char **,
+static void decode_location_default (struct breakpoint *, char **,
 				     struct symtabs_and_lines *);
 
 static void clear_command (char *, int);
@@ -9623,8 +9623,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
   TRY
     {
-      ops->create_sals_from_address (&arg, &canonical, type_wanted,
-				     addr_start, &copy_arg);
+      ops->create_sals_from_location (&arg, &canonical, type_wanted,
+				      addr_start, &copy_arg);
     }
   CATCH (e, RETURN_MASK_ERROR)
     {
@@ -12728,11 +12728,11 @@ base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
 }
 
 static void
-base_breakpoint_create_sals_from_address (char **arg,
-					  struct linespec_result *canonical,
-					  enum bptype type_wanted,
-					  char *addr_start,
-					  char **copy_arg)
+base_breakpoint_create_sals_from_location (char **arg,
+					   struct linespec_result *canonical,
+					   enum bptype type_wanted,
+					   char *addr_start,
+					   char **copy_arg)
 {
   internal_error_pure_virtual_called ();
 }
@@ -12754,7 +12754,7 @@ base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-base_breakpoint_decode_linespec (struct breakpoint *b, char **s,
+base_breakpoint_decode_location (struct breakpoint *b, char **s,
 				 struct symtabs_and_lines *sals)
 {
   internal_error_pure_virtual_called ();
@@ -12792,9 +12792,9 @@ struct breakpoint_ops base_breakpoint_ops =
   base_breakpoint_print_one_detail,
   base_breakpoint_print_mention,
   base_breakpoint_print_recreate,
-  base_breakpoint_create_sals_from_address,
+  base_breakpoint_create_sals_from_location,
   base_breakpoint_create_breakpoints_sal,
-  base_breakpoint_decode_linespec,
+  base_breakpoint_decode_location,
   base_breakpoint_explains_signal,
   base_breakpoint_after_condition_true,
 };
@@ -12964,12 +12964,12 @@ bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
 }
 
 static void
-bkpt_create_sals_from_address (char **arg,
+bkpt_create_sals_from_location (char **arg,
 			       struct linespec_result *canonical,
 			       enum bptype type_wanted,
 			       char *addr_start, char **copy_arg)
 {
-  create_sals_from_address_default (arg, canonical, type_wanted,
+  create_sals_from_location_default (arg, canonical, type_wanted,
 				    addr_start, copy_arg);
 }
 
@@ -12995,10 +12995,10 @@ bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-bkpt_decode_linespec (struct breakpoint *b, char **s,
+bkpt_decode_location (struct breakpoint *b, char **s,
 		      struct symtabs_and_lines *sals)
 {
-  decode_linespec_default (b, s, sals);
+  decode_location_default (b, s, sals);
 }
 
 /* Virtual table for internal breakpoints.  */
@@ -13198,10 +13198,10 @@ bkpt_probe_remove_location (struct bp_location *bl)
 }
 
 static void
-bkpt_probe_create_sals_from_address (char **arg,
-				     struct linespec_result *canonical,
-				     enum bptype type_wanted,
-				     char *addr_start, char **copy_arg)
+bkpt_probe_create_sals_from_location (char **arg,
+				      struct linespec_result *canonical,
+				      enum bptype type_wanted,
+				      char *addr_start, char **copy_arg)
 {
   struct linespec_sals lsal;
 
@@ -13214,7 +13214,7 @@ bkpt_probe_create_sals_from_address (char **arg,
 }
 
 static void
-bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
+bkpt_probe_decode_location (struct breakpoint *b, char **s,
 			    struct symtabs_and_lines *sals)
 {
   *sals = parse_probes (s, NULL);
@@ -13307,12 +13307,12 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
 }
 
 static void
-tracepoint_create_sals_from_address (char **arg,
+tracepoint_create_sals_from_location (char **arg,
 				     struct linespec_result *canonical,
 				     enum bptype type_wanted,
 				     char *addr_start, char **copy_arg)
 {
-  create_sals_from_address_default (arg, canonical, type_wanted,
+  create_sals_from_location_default (arg, canonical, type_wanted,
 				    addr_start, copy_arg);
 }
 
@@ -13338,10 +13338,10 @@ tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-tracepoint_decode_linespec (struct breakpoint *b, char **s,
+tracepoint_decode_location (struct breakpoint *b, char **s,
 			    struct symtabs_and_lines *sals)
 {
-  decode_linespec_default (b, s, sals);
+  decode_location_default (b, s, sals);
 }
 
 struct breakpoint_ops tracepoint_breakpoint_ops;
@@ -13350,22 +13350,22 @@ struct breakpoint_ops tracepoint_breakpoint_ops;
    static probe.  */
 
 static void
-tracepoint_probe_create_sals_from_address (char **arg,
-					   struct linespec_result *canonical,
-					   enum bptype type_wanted,
-					   char *addr_start, char **copy_arg)
+tracepoint_probe_create_sals_from_location (char **arg,
+					    struct linespec_result *canonical,
+					    enum bptype type_wanted,
+					    char *addr_start, char **copy_arg)
 {
   /* We use the same method for breakpoint on probes.  */
-  bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
-				       addr_start, copy_arg);
+  bkpt_probe_create_sals_from_location (arg, canonical, type_wanted,
+					addr_start, copy_arg);
 }
 
 static void
-tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
+tracepoint_probe_decode_location (struct breakpoint *b, char **s,
 				  struct symtabs_and_lines *sals)
 {
   /* We use the same method for breakpoint on probes.  */
-  bkpt_probe_decode_linespec (b, s, sals);
+  bkpt_probe_decode_location (b, s, sals);
 }
 
 static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
@@ -13451,10 +13451,10 @@ dprintf_after_condition_true (struct bpstats *bs)
    markers (`-m').  */
 
 static void
-strace_marker_create_sals_from_address (char **arg,
-					struct linespec_result *canonical,
-					enum bptype type_wanted,
-					char *addr_start, char **copy_arg)
+strace_marker_create_sals_from_location (char **arg,
+					 struct linespec_result *canonical,
+					 enum bptype type_wanted,
+					 char *addr_start, char **copy_arg)
 {
   struct linespec_sals lsal;
 
@@ -13527,7 +13527,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 }
 
 static void
-strace_marker_decode_linespec (struct breakpoint *b, char **s,
+strace_marker_decode_location (struct breakpoint *b, char **s,
 			       struct symtabs_and_lines *sals)
 {
   struct tracepoint *tp = (struct tracepoint *) b;
@@ -14072,7 +14072,7 @@ update_breakpoint_locations (struct breakpoint *b,
    On return, FOUND will be 1 if any SaL was found, zero otherwise.  */
 
 static struct symtabs_and_lines
-addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
+location_to_sals (struct breakpoint *b, char *addr_string, int *found)
 {
   char *s;
   struct symtabs_and_lines sals = {0};
@@ -14083,7 +14083,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
 
   TRY
     {
-      b->ops->decode_linespec (b, &s, &sals);
+      b->ops->decode_location (b, &s, &sals);
     }
   CATCH (e, RETURN_MASK_ERROR)
     {
@@ -14165,7 +14165,7 @@ breakpoint_re_set_default (struct breakpoint *b)
   struct symtabs_and_lines expanded = {0};
   struct symtabs_and_lines expanded_end = {0};
 
-  sals = addr_string_to_sals (b, b->addr_string, &found);
+  sals = location_to_sals (b, b->addr_string, &found);
   if (found)
     {
       make_cleanup (xfree, sals.sals);
@@ -14174,7 +14174,7 @@ breakpoint_re_set_default (struct breakpoint *b)
 
   if (b->addr_string_range_end)
     {
-      sals_end = addr_string_to_sals (b, b->addr_string_range_end, &found);
+      sals_end = location_to_sals (b, b->addr_string_range_end, &found);
       if (found)
 	{
 	  make_cleanup (xfree, sals_end.sals);
@@ -14189,7 +14189,7 @@ breakpoint_re_set_default (struct breakpoint *b)
    calls parse_breakpoint_sals.  Return 1 for success, zero for failure.  */
 
 static void
-create_sals_from_address_default (char **arg,
+create_sals_from_location_default (char **arg,
 				  struct linespec_result *canonical,
 				  enum bptype type_wanted,
 				  char *addr_start, char **copy_arg)
@@ -14222,10 +14222,10 @@ create_breakpoints_sal_default (struct gdbarch *gdbarch,
 }
 
 /* Decode the line represented by S by calling decode_line_full.  This is the
-   default function for the `decode_linespec' method of breakpoint_ops.  */
+   default function for the `decode_location' method of breakpoint_ops.  */
 
 static void
-decode_linespec_default (struct breakpoint *b, char **s,
+decode_location_default (struct breakpoint *b, char **s,
 			 struct symtabs_and_lines *sals)
 {
   struct linespec_result canonical;
@@ -15605,9 +15605,9 @@ initialize_breakpoint_ops (void)
   ops->insert_location = bkpt_insert_location;
   ops->remove_location = bkpt_remove_location;
   ops->breakpoint_hit = bkpt_breakpoint_hit;
-  ops->create_sals_from_address = bkpt_create_sals_from_address;
+  ops->create_sals_from_location = bkpt_create_sals_from_location;
   ops->create_breakpoints_sal = bkpt_create_breakpoints_sal;
-  ops->decode_linespec = bkpt_decode_linespec;
+  ops->decode_location = bkpt_decode_location;
 
   /* The breakpoint_ops structure to be used in regular breakpoints.  */
   ops = &bkpt_breakpoint_ops;
@@ -15655,8 +15655,8 @@ initialize_breakpoint_ops (void)
   *ops = bkpt_breakpoint_ops;
   ops->insert_location = bkpt_probe_insert_location;
   ops->remove_location = bkpt_probe_remove_location;
-  ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
-  ops->decode_linespec = bkpt_probe_decode_linespec;
+  ops->create_sals_from_location = bkpt_probe_create_sals_from_location;
+  ops->decode_location = bkpt_probe_decode_location;
 
   /* Watchpoints.  */
   ops = &watchpoint_breakpoint_ops;
@@ -15694,22 +15694,22 @@ initialize_breakpoint_ops (void)
   ops->print_one_detail = tracepoint_print_one_detail;
   ops->print_mention = tracepoint_print_mention;
   ops->print_recreate = tracepoint_print_recreate;
-  ops->create_sals_from_address = tracepoint_create_sals_from_address;
+  ops->create_sals_from_location = tracepoint_create_sals_from_location;
   ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
-  ops->decode_linespec = tracepoint_decode_linespec;
+  ops->decode_location = tracepoint_decode_location;
 
   /* Probe tracepoints.  */
   ops = &tracepoint_probe_breakpoint_ops;
   *ops = tracepoint_breakpoint_ops;
-  ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
-  ops->decode_linespec = tracepoint_probe_decode_linespec;
+  ops->create_sals_from_location = tracepoint_probe_create_sals_from_location;
+  ops->decode_location = tracepoint_probe_decode_location;
 
   /* Static tracepoints with marker (`-m').  */
   ops = &strace_marker_breakpoint_ops;
   *ops = tracepoint_breakpoint_ops;
-  ops->create_sals_from_address = strace_marker_create_sals_from_address;
+  ops->create_sals_from_location = strace_marker_create_sals_from_location;
   ops->create_breakpoints_sal = strace_marker_create_breakpoints_sal;
-  ops->decode_linespec = strace_marker_decode_linespec;
+  ops->decode_location = strace_marker_decode_location;
 
   /* Fork catchpoints.  */
   ops = &catch_fork_breakpoint_ops;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 562a6b6..6f144bd 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -574,14 +574,14 @@ struct breakpoint_ops
   /* Print to FP the CLI command that recreates this breakpoint.  */
   void (*print_recreate) (struct breakpoint *, struct ui_file *fp);
 
-  /* Create SALs from address string, storing the result in linespec_result.
+  /* Create SALs from location, storing the result in linespec_result.
 
      For an explanation about the arguments, see the function
-     `create_sals_from_address_default'.
+     `create_sals_from_location_default'.
 
      This function is called inside `create_breakpoint'.  */
-  void (*create_sals_from_address) (char **, struct linespec_result *,
-				    enum bptype, char *, char **);
+  void (*create_sals_from_location) (char **, struct linespec_result *,
+				     enum bptype, char *, char **);
 
   /* This method will be responsible for creating a breakpoint given its SALs.
      Usually, it just calls `create_breakpoints_sal' (for ordinary
@@ -597,12 +597,12 @@ struct breakpoint_ops
 				  int, const struct breakpoint_ops *,
 				  int, int, int, unsigned);
 
-  /* Given the address string (second parameter), this method decodes it
+  /* Given the location (second parameter), this method decodes it
      and provides the SAL locations related to it.  For ordinary breakpoints,
      it calls `decode_line_full'.
 
-     This function is called inside `addr_string_to_sals'.  */
-  void (*decode_linespec) (struct breakpoint *, char **,
+     This function is called inside `location_to_sals'.  */
+  void (*decode_location) (struct breakpoint *, char **,
 			   struct symtabs_and_lines *);
 
   /* Return true if this breakpoint explains a signal.  See

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 4/9] Explicit locations: introduce address locations
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (4 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 5/9] Explicit locations: introduce probe locations Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  5:45   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch adds support for address locations, of the form "*ADDR".
[Support for address linespecs has been removed/replaced by this "new"
location type.] This patch also converts any existing address locations
from its previous linespec type.

gdb/ChangeLog:

	* breakpoint.c (create_thread_event_breakpoint): Convert
	linespec to address location.
	(init_breakpoint_sal): Likewise.
	* linespec.c (canonicalize_linespec): Do not handle address
	locations here.
	(convert_address_location_to_sals): New function; contents moved
	from ...
	(convert_linespc_to_sals): ... here.
	(parse_linespec): Remove address locations from linespec grammar.
	Remove handling of address locations.
	(linespec_lex_to_end): Remove handling of address linespecs.
	(event_location_to_sals): Handle ADDRESS_LOCATION.
	(linespec_expression_to_pc): Export.
	* linespec.h (linespec_expression_to_pc): Add declaration.
	* location.c (struct event_location.u) <address>: New member.
	(new_address_location, get_address_location): New functions.
	(copy_event_location): Handle address locations.
	(delete_event_location): Likewise.
	(event_location_to_string): Likewise.
	(string_to_event_location): Likewise.
	(event_location_empty_p): Likewise.
	* location.h (enum event_location_type): Add ADDRESS_LOCATION.
	(new_address_location, get_address_location): Declare.
	* python/py-finishbreakpoint.c (bpfinishpy_init): Convert linespec
	to address location.
	* spu-tdep.c (spu_catch_start): Likewise.
---
 gdb/breakpoint.c                 |   18 ----
 gdb/linespec.c                   |  192 +++++++++++++++-----------------------
 gdb/linespec.h                   |    5 +
 gdb/location.c                   |   61 ++++++++++++
 gdb/location.h                   |   17 +++
 gdb/python/py-finishbreakpoint.c |    8 --
 gdb/spu-tdep.c                   |    5 -
 7 files changed, 163 insertions(+), 143 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 549bfd0..c1d8ddc 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7656,19 +7656,14 @@ delete_std_terminate_breakpoint (void)
 struct breakpoint *
 create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
-  char *tmp;
   struct breakpoint *b;
-  struct cleanup *cleanup;
 
   b = create_internal_breakpoint (gdbarch, address, bp_thread_event,
 				  &internal_breakpoint_ops);
 
   b->enable_state = bp_enabled;
   /* location has to be used or breakpoint_re_set will delete me.  */
-  tmp = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
-  cleanup = make_cleanup (xfree, tmp);
-  b->location = new_linespec_location (&tmp);
-  do_cleanups (cleanup);
+  b->location = new_address_location (b->loc->address);
 
   update_global_location_list_nothrow (UGLL_MAY_INSERT);
 
@@ -9247,16 +9242,7 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
   if (location != NULL)
     b->location = location;
   else
-    {
-      char *tmp;
-      struct cleanup *cleanup;
-
-      tmp = xstrprintf ("*%s",
-			    paddress (b->loc->gdbarch, b->loc->address));
-      cleanup = make_cleanup (xfree, tmp);
-      b->location = new_linespec_location (&tmp);
-      do_cleanups (cleanup);
-   }
+    b->location = new_address_location (b->loc->address);
   b->filter = filter;
 }
 
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 5949594..c4cbe13 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -312,7 +312,7 @@ static void iterate_over_file_blocks (struct symtab *symtab,
 static void initialize_defaults (struct symtab **default_symtab,
 				 int *default_line);
 
-static CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
+CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
 
 static struct symtabs_and_lines decode_objc (struct linespec_state *self,
 					     linespec_p ls,
@@ -1789,79 +1789,69 @@ static void
 canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 {
   char *tmp;
+  struct ui_file *buf;
+  int need_colon = 0;
+  struct cleanup *cleanup;
 
   /* If canonicalization was not requested, no need to do anything.  */
   if (!state->canonical)
     return;
 
-  /* Shortcut expressions, which can only appear by themselves.  */
-  if (ls->expression != NULL)
+  buf = mem_fileopen ();
+  cleanup = make_cleanup_ui_file_delete (buf);
+
+  if (ls->source_filename)
     {
-      tmp = ASTRDUP (ls->expression);
-      state->canonical->location = new_linespec_location (&tmp);
+      fputs_unfiltered (ls->source_filename, buf);
+      need_colon = 1;
     }
-  else
-    {
-      struct ui_file *buf;
-      int need_colon = 0;
-      struct cleanup *cleanup;
 
-      buf = mem_fileopen ();
-      cleanup = make_cleanup_ui_file_delete (buf);
+  if (ls->function_name)
+    {
+      if (need_colon)
+	fputc_unfiltered (':', buf);
+      fputs_unfiltered (ls->function_name, buf);
+      need_colon = 1;
+    }
 
-      if (ls->source_filename)
-	{
-	  fputs_unfiltered (ls->source_filename, buf);
-	  need_colon = 1;
-	}
+  if (ls->label_name)
+    {
+      if (need_colon)
+	fputc_unfiltered (':', buf);
 
-      if (ls->function_name)
+      if (ls->function_name == NULL)
 	{
-	  if (need_colon)
-	    fputc_unfiltered (':', buf);
-	  fputs_unfiltered (ls->function_name, buf);
-	  need_colon = 1;
+	  struct symbol *s;
+
+	  /* No function was specified, so add the symbol name.  */
+	  gdb_assert (ls->labels.function_symbols != NULL
+		      && (VEC_length (symbolp, ls->labels.function_symbols)
+			  == 1));
+	  s = VEC_index (symbolp, ls->labels.function_symbols, 0);
+	  fputs_unfiltered (SYMBOL_NATURAL_NAME (s), buf);
+	  fputc_unfiltered (':', buf);
 	}
 
-      if (ls->label_name)
-	{
-	  if (need_colon)
-	    fputc_unfiltered (':', buf);
-
-	  if (ls->function_name == NULL)
-	    {
-	      struct symbol *s;
-
-	      /* No function was specified, so add the symbol name.  */
-	      gdb_assert (ls->labels.function_symbols != NULL
-			  && (VEC_length (symbolp, ls->labels.function_symbols)
-			      == 1));
-	      s = VEC_index (symbolp, ls->labels.function_symbols, 0);
-	      fputs_unfiltered (SYMBOL_NATURAL_NAME (s), buf);
-	      fputc_unfiltered (':', buf);
-	    }
-
-	  fputs_unfiltered (ls->label_name, buf);
-	  need_colon = 1;
-	  state->canonical->special_display = 1;
-	}
-
-      if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
-	{
-	  if (need_colon)
-	    fputc_unfiltered (':', buf);
-	  fprintf_filtered (buf, "%s%d",
-			    (ls->line_offset.sign == LINE_OFFSET_NONE ? ""
-			     : (ls->line_offset.sign
-				== LINE_OFFSET_PLUS ? "+" : "-")),
-			    ls->line_offset.offset);
-	}
+      fputs_unfiltered (ls->label_name, buf);
+      need_colon = 1;
+      state->canonical->special_display = 1;
+    }
 
-      tmp = ui_file_xstrdup (buf, NULL);
-      make_cleanup (xfree, tmp);
-      state->canonical->location = new_linespec_location (&tmp);
-      do_cleanups (cleanup);
+  if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
+    {
+      if (need_colon)
+	fputc_unfiltered (':', buf);
+      fprintf_filtered (buf, "%s%d",
+			(ls->line_offset.sign == LINE_OFFSET_NONE ? ""
+			 : (ls->line_offset.sign
+			    == LINE_OFFSET_PLUS ? "+" : "-")),
+			ls->line_offset.offset);
     }
+
+  tmp = ui_file_xstrdup (buf, NULL);
+  make_cleanup (xfree, tmp);
+  state->canonical->location = new_linespec_location (&tmp);
+  do_cleanups (cleanup);
 }
 
 /* Given a line offset in LS, construct the relevant SALs.  */
@@ -2015,6 +2005,24 @@ create_sals_line_offset (struct linespec_state *self,
   return values;
 }
 
+/* Convert the given ADDRESS into SaLs.  */
+
+static struct symtabs_and_lines
+convert_address_location_to_sals (struct linespec_state *self,
+				  CORE_ADDR address)
+{
+  struct symtab_and_line sal;
+  struct symtabs_and_lines sals = {NULL, 0};
+
+  sal = find_pc_line (address, 0);
+  sal.pc = address;
+  sal.section = find_pc_overlay (address);
+  sal.explicit_pc = 1;
+  add_sal_to_sals (self, &sals, &sal, core_addr_to_string (address), 1);
+
+  return sals;
+}
+
 /* Create and return SALs from the linespec LS.  */
 
 static struct symtabs_and_lines
@@ -2022,18 +2030,7 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 {
   struct symtabs_and_lines sals = {NULL, 0};
 
-  if (ls->expression != NULL)
-    {
-      struct symtab_and_line sal;
-
-      /* We have an expression.  No other attribute is allowed.  */
-      sal = find_pc_line (ls->expr_pc, 0);
-      sal.pc = ls->expr_pc;
-      sal.section = find_pc_overlay (ls->expr_pc);
-      sal.explicit_pc = 1;
-      add_sal_to_sals (state, &sals, &sal, ls->expression, 1);
-    }
-  else if (ls->labels.label_symbols != NULL)
+  if (ls->labels.label_symbols != NULL)
     {
       /* We have just a bunch of functions/methods or labels.  */
       int i;
@@ -2131,8 +2128,7 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 
    The basic grammar of linespecs:
 
-   linespec -> expr_spec | var_spec | basic_spec
-   expr_spec -> '*' STRING
+   linespec -> var_spec | basic_spec
    var_spec -> '$' (STRING | NUMBER)
 
    basic_spec -> file_offset_spec | function_spec | label_spec
@@ -2223,33 +2219,7 @@ parse_linespec (linespec_parser *parser, const char *arg)
   token = linespec_lexer_lex_one (parser);
 
   /* It must be either LSTOKEN_STRING or LSTOKEN_NUMBER.  */
-  if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '*')
-    {
-      char *expr;
-      const char *copy;
-
-      /* User specified an expression, *EXPR.  */
-      copy = expr = copy_token_string (token);
-      cleanup = make_cleanup (xfree, expr);
-      PARSER_RESULT (parser)->expr_pc = linespec_expression_to_pc (&copy);
-      discard_cleanups (cleanup);
-      PARSER_RESULT (parser)->expression = expr;
-
-      /* This is a little hacky/tricky.  If linespec_expression_to_pc
-	 did not evaluate the entire token, then we must find the
-	 string COPY inside the original token buffer.  */
-      if (*copy != '\0')
-	{
-	  PARSER_STREAM (parser) = strstr (parser->lexer.saved_arg, copy);
-	  gdb_assert (PARSER_STREAM (parser) != NULL);
-	}
-
-      /* Consume the token.  */
-      linespec_lexer_consume_token (parser);
-
-      goto convert_to_sals;
-    }
-  else if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '$')
+  if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '$')
     {
       char *var;
 
@@ -2472,20 +2442,6 @@ linespec_lex_to_end (char **stringp)
 	  token = linespec_lexer_peek_token (&parser);
 	  if (token.type == LSTOKEN_COMMA)
 	    break;
-
-	  /* For addresses advance the parser stream past
-	     any parsed input and stop lexing.  */
-	  if (token.type == LSTOKEN_STRING
-	      && *LS_TOKEN_STOKEN (token).ptr == '*')
-	    {
-	      const char *arg;
-
-	      arg = *stringp;
-	      (void) linespec_expression_to_pc (&arg);
-	      PARSER_STREAM (&parser) = arg;
-	      break;
-	    }
-
 	  token = linespec_lexer_consume_token (&parser);
 	}
       while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
@@ -2524,6 +2480,12 @@ event_location_to_sals (linespec_parser *parser,
       }
       break;
 
+    case ADDRESS_LOCATION:
+      result
+	= convert_address_location_to_sals (PARSER_STATE (parser),
+					    get_address_location (location));
+      break;
+
     default:
       gdb_assert_not_reached ("unhandled event location type");
     }
@@ -2709,7 +2671,7 @@ initialize_defaults (struct symtab **default_symtab, int *default_line)
 /* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
    advancing EXP_PTR past any parsed text.  */
 
-static CORE_ADDR
+CORE_ADDR
 linespec_expression_to_pc (const char **exp_ptr)
 {
   if (current_program_space->executing_startup)
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 840bae5..391ed26 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -161,4 +161,9 @@ extern const char *linespec_lexer_lex_keyword (const char *p);
    STRINGP will be advanced to this point.  */
 
 extern void linespec_lex_to_end (char **stringp);
+
+/* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
+   advancing EXP_PTR past any parsed text.  */
+
+extern CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
 #endif /* defined (LINESPEC_H) */
diff --git a/gdb/location.c b/gdb/location.c
index 39e09c1..c1f4e19 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -45,6 +45,10 @@ struct event_location
        probes.  */
     char *addr_string;
 #define EL_LINESPEC(PTR) ((PTR)->u.addr_string)
+
+    /* An address in the inferior.  */
+    CORE_ADDR address;
+#define EL_ADDRESS(PTR) (PTR)->u.address
   } u;
 
   /* Cached string representation of this location.  This is used, e.g., to
@@ -95,6 +99,28 @@ get_linespec_location (const struct event_location *location)
 /* See description in location.h.  */
 
 struct event_location *
+new_address_location (CORE_ADDR addr)
+{
+  struct event_location *location;
+
+  location = XCNEW (struct event_location);
+  EL_TYPE (location) = ADDRESS_LOCATION;
+  EL_ADDRESS (location) = addr;
+  return location;
+}
+
+/* See description in location.h.  */
+
+CORE_ADDR
+get_address_location (const struct event_location *location)
+{
+  gdb_assert (EL_TYPE (location) == ADDRESS_LOCATION);
+  return EL_ADDRESS (location);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
 copy_event_location (const struct event_location *src)
 {
   struct event_location *dst;
@@ -111,6 +137,10 @@ copy_event_location (const struct event_location *src)
 	EL_LINESPEC (dst) = xstrdup (EL_LINESPEC (src));
       break;
 
+    case ADDRESS_LOCATION:
+      EL_ADDRESS (dst) = EL_ADDRESS (src);
+      break;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
@@ -151,6 +181,10 @@ delete_event_location (struct event_location *location)
 	  xfree (EL_LINESPEC (location));
 	  break;
 
+	case ADDRESS_LOCATION:
+	  /* Nothing to do.  */
+	  break;
+
 	default:
 	  gdb_assert_not_reached ("unknown event location type");
 	}
@@ -176,6 +210,12 @@ event_location_to_string_const (const struct event_location *location)
 	result = xstrdup (EL_LINESPEC (location));
       break;
 
+    case ADDRESS_LOCATION:
+      result
+	= xstrprintf ("*%s",
+		      core_addr_to_string (EL_ADDRESS (location)));
+      break;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
@@ -203,7 +243,23 @@ string_to_event_location (char **stringp,
 {
   struct event_location *location;
 
-  location = new_linespec_location (stringp);
+  /* First, check if the string is an address location.  */
+  if (*stringp != NULL && **stringp == '*')
+    {
+      const char *arg, *orig;
+      CORE_ADDR addr;
+
+      orig = arg = *stringp;
+      addr = linespec_expression_to_pc (&arg);
+      location = new_address_location (addr);
+      *stringp += arg - orig;
+    }
+  else
+    {
+      /* Everything else is a linespec.  */
+      location = new_linespec_location (stringp);
+    }
+
   return location;
 }
 
@@ -218,6 +274,9 @@ event_location_empty_p (const struct event_location *location)
       /* Linespecs are never "empty."  (NULL is a valid linespec)  */
       return 0;
 
+    case ADDRESS_LOCATION:
+      return 0;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
diff --git a/gdb/location.h b/gdb/location.h
index 992f21e..39db10e 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -28,7 +28,10 @@ struct event_location;
 enum event_location_type
 {
   /* A traditional linespec.  */
-  LINESPEC_LOCATION
+  LINESPEC_LOCATION,
+
+  /* An address in the inferior.  */
+  ADDRESS_LOCATION
 };
 
 /* Return the type of the given event location.  */
@@ -64,6 +67,18 @@ extern struct event_location *
 extern const char *
   get_linespec_location (const struct event_location *location);
 
+/* Create a new address location.  The return result is malloc'd
+   and should be freed with delete_event_location.  */
+
+extern struct event_location *
+  new_address_location (CORE_ADDR addr);
+
+/* Return the address location (a CORE_ADDR) of the given event_location
+   (which must be of type ADDRESS_LOCATION).  */
+
+extern CORE_ADDR
+  get_address_location (const struct event_location *location);
+
 /* Free an event location and any associated data.  */
 
 extern void delete_event_location (struct event_location *location);
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index 2160ef5..e1629b0 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -166,8 +166,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
   struct frame_id frame_id;
   PyObject *internal = NULL;
   int internal_bp = 0;
-  CORE_ADDR finish_pc, pc;
-  char small_buf[100], *p;
+  CORE_ADDR pc;
   struct symbol *function;
 
   if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
@@ -298,10 +297,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       struct cleanup *back_to;
 
       /* Set a breakpoint on the return address.  */
-      finish_pc = get_frame_pc (prev_frame);
-      xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc));
-      p = small_buf;
-      location = new_linespec_location (&p);
+      location = new_address_location (get_frame_pc (prev_frame));
       back_to = make_cleanup_delete_event_location (location);
       create_breakpoint (python_gdbarch,
                          location, NULL, thread, NULL,
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 83f4c6e..7421973 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -1954,7 +1954,6 @@ spu_catch_start (struct objfile *objfile)
 {
   struct bound_minimal_symbol minsym;
   struct compunit_symtab *cust;
-  char buf[32], *p;
   CORE_ADDR pc;
   struct event_location *location;
   struct cleanup *back_to;
@@ -2001,9 +2000,7 @@ spu_catch_start (struct objfile *objfile)
 
   /* Use a numerical address for the set_breakpoint command to avoid having
      the breakpoint re-set incorrectly.  */
-  xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
-  p = buf;
-  location = new_linespec_location (&p);
+  location = new_address_location (pc);
   back_to = make_cleanup_delete_event_location (location);
   create_breakpoint (get_objfile_arch (objfile), location,
 		     NULL /* cond_string */, -1 /* thread */,

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
  2015-05-07 18:05 ` [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  6:13   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 8/9] Explicit locations: MI support for " Keith Seitz
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch add support for explicit locations and switches many linespec
locations to this new location type.  This patch also converts all
linespec locations entered by the user to an explicit representation
internally (thus bypassing the linespec parser when resetting the
breakpoint).

This patch does not introduce any user-visible changes.


gdb/ChangeLog:

	* break-catch-throw.c (re_set_exception_catchpoint): Convert
	linespec into explicit location.
	* breakpoint.c (create_overlay_breakpoint): Likewise.
	(create_longjmp_master_breakpoint): Likewise.
	(create_std_terminate_master_breakpoint): Likewise.
	(create_exception_master_breakpoint): Likewise.
	(create_breakpoint): For pending explicit locations, append extra_string
	to the canonical representation.
	(update_static_tracepoint): Convert linespec into explicit location.
	(location_to_sals): Save the string representation of the location
	for pending locations which were resolved.
	* linespec.c (enum offset_relative_sign): Move to location.h.
	(struct line_offset): Likewise.
	(struct linespec) <expression, expr_pc, source_filename>
	<function_name, label_name, line_offset>: Replace with ...
	<explicit>: ... this.
	<is_linespec>: New member.
	(PARSER_EXPLICIT): New accessor macro.
	(undefined_label_error): New function.
	(source_file_not_found_error): New function.
	(linespec_parse_basic): The parser result is now an explicit location.
	Use PARSER_EXPLICIT to access it.
	Use undefined_label_error.
	(canonicalize_linespec): Convert canonical linespec into explicit
	location.
	Move string representation of location to explicit_location_to_linespec
	and use it and explicit_location_to_string to save string
	representations of the canonical location.
	(create_sals_line_offset): `ls' contains an explicit location.
	Update all references.
	(convert_linespec_to_sals): Likewise.
	(convert_explicit_location_to_sals): New function.
	(parse_linespec): Use PARSER_EXPLICIT to access the parser
	result's explicit location.
	(linespec_state_constructor): Initialize is_linespec.
	Use PARSER_EXPLICIT.
	(linespec_parser_delete): Use PARSER_EXPLICIT to access the parser's
	result.
	(event_location_to_sals): For linespec locations, set is_linespec.
	Handle explicit locations.
	(decode_objc): 'ls' contains an explicit location now. Update all
	references.
	(symtabs_from_filename): Use source_file_not_found_error.
	* location.c (struct event_location.u) <explicit>: New member.
	(initialize_explicit_location): New function.
	(initialize_event_location): Initialize explicit locations.
	(new_explicit_location, get_explicit_location)
	(get_explicit_location_const): New functions.
	(explicit_to_string_internal): New function; most of contents moved
	from canonicalize_linespec.
	(explicit_location_to_string): New function.
	(explicit_location_to_linespec): New function.
	(copy_event_location): Handle explicit locations.
	(delete_event_location): Likewise.
	(event_location_to_string_const): Likewise.
	(event_location_empty_p): Likewise.
	* location.h (enum offset_relative_sign): Move here from linespec.h.
	(struct line_offset): Likewise.
	(enum event_location_type): Add EXPLICIT_LOCATION.
	(struct explicit_location): New structure.
	(explicit_location_to_string): Declare.
	(explicit_location_to_linespec): Declare.
	(new_explicit_location, get_explicit_locationp
	(get_explicit_location_const, initialize_explicit_location): Declare.
---
 gdb/break-catch-throw.c |    7 +
 gdb/breakpoint.c        |   43 ++++---
 gdb/linespec.c          |  302 ++++++++++++++++++++++++++---------------------
 gdb/location.c          |  178 ++++++++++++++++++++++++++++
 gdb/location.h          |   90 +++++++++++++-
 5 files changed, 456 insertions(+), 164 deletions(-)

diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 07a8f05..209c3e3 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -229,9 +229,12 @@ re_set_exception_catchpoint (struct breakpoint *self)
 	 catchpoint mode.  */
       TRY
 	{
-	  char *spec = ASTRDUP (exception_functions[kind].function);
+	  struct explicit_location explicit;
 
-	  location = new_linespec_location (&spec);
+	  initialize_explicit_location (&explicit);
+	  explicit.function_name
+	    = ASTRDUP (exception_functions[kind].function);
+	  location = new_explicit_location (&explicit);
 	  cleanup = make_cleanup_delete_event_location (location);
 	  self->ops->decode_location (self, location, &sals);
 	  do_cleanups (cleanup);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 9f879ed..58c3cd7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3414,7 +3414,7 @@ create_overlay_event_breakpoint (void)
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
-      char *p;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3439,8 +3439,9 @@ create_overlay_event_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_overlay_event,
 				      &internal_breakpoint_ops);
-      p = ASTRDUP (func_name);
-      b->location = new_linespec_location (&p);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
 
       if (overlay_debugging == ovly_auto)
         {
@@ -3537,7 +3538,7 @@ create_longjmp_master_breakpoint (void)
 	  struct breakpoint *b;
 	  const char *func_name;
 	  CORE_ADDR addr;
-	  char *p;
+	  struct explicit_location explicit;
 
 	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
 	    continue;
@@ -3560,8 +3561,9 @@ create_longjmp_master_breakpoint (void)
 	  addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
 	  b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
 					  &internal_breakpoint_ops);
-	  p = ASTRDUP (func_name);
-	  b->location = new_linespec_location (&p);
+	  initialize_explicit_location (&explicit);
+	  explicit.function_name = ASTRDUP (func_name);
+	  b->location = new_explicit_location (&explicit);
 	  b->enable_state = bp_disabled;
 	}
     }
@@ -3592,7 +3594,7 @@ create_std_terminate_master_breakpoint (void)
     {
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
-      char *p;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3618,8 +3620,9 @@ create_std_terminate_master_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_std_terminate_master,
 				      &internal_breakpoint_ops);
-      p = ASTRDUP (func_name);
-      b->location = new_linespec_location (&p);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
   }
@@ -3643,7 +3646,7 @@ create_exception_master_breakpoint (void)
       struct gdbarch *gdbarch;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
-      char *p;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3724,8 +3727,9 @@ create_exception_master_breakpoint (void)
 						 &current_target);
       b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 				      &internal_breakpoint_ops);
-      p = ASTRDUP (func_name);
-      b->location = new_linespec_location (&p);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
 
@@ -13933,12 +13937,11 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 
       if (!VEC_empty(static_tracepoint_marker_p, markers))
 	{
-	  char *p, *tmp;
 	  struct symtab_and_line sal2;
 	  struct symbol *sym;
 	  struct static_tracepoint_marker *tpmarker;
 	  struct ui_out *uiout = current_uiout;
-	  struct cleanup *cleanup;
+	  struct explicit_location explicit;
 
 	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
 
@@ -13980,12 +13983,12 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 	  b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
 
 	  delete_event_location (b->location);
-	  p = tmp = xstrprintf ("%s:%d",
-				symtab_to_filename_for_display (sal2.symtab),
-				b->loc->line_number);
-	  cleanup = make_cleanup (xfree, tmp);
-	  b->location = new_linespec_location (&tmp);
-	  do_cleanups (cleanup);
+	  initialize_explicit_location (&explicit);
+	  explicit.source_filename
+	    = ASTRDUP (symtab_to_filename_for_display (sal2.symtab));
+	  explicit.line_offset.offset = b->loc->line_number;
+	  explicit.line_offset.sign = LINE_OFFSET_NONE;
+	  b->location = new_explicit_location (&explicit);
 
 	  /* Might be nice to check if function changed, and warn if
 	     so.  */
diff --git a/gdb/linespec.c b/gdb/linespec.c
index fa7e3f4..a7e6248 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -65,73 +65,26 @@ typedef struct bound_minimal_symbol bound_minimal_symbol_d;
 
 DEF_VEC_O (bound_minimal_symbol_d);
 
-/* An enumeration of possible signs for a line offset.  */
-enum offset_relative_sign
-{
-  /* No sign  */
-  LINE_OFFSET_NONE,
-
-  /* A plus sign ("+")  */
-  LINE_OFFSET_PLUS,
-
-  /* A minus sign ("-")  */
-  LINE_OFFSET_MINUS,
-
-  /* A special "sign" for unspecified offset.  */
-  LINE_OFFSET_UNKNOWN
-};
-
-/* A line offset in a linespec.  */
-
-struct line_offset
-{
-  /* Line offset and any specified sign.  */
-  int offset;
-  enum offset_relative_sign sign;
-};
-
 /* A linespec.  Elements of this structure are filled in by a parser
    (either parse_linespec or some other function).  The structure is
    then converted into SALs by convert_linespec_to_sals.  */
 
 struct linespec
 {
-  /* An expression and the resulting PC.  Specifying an expression
-     currently precludes the use of other members.  */
-
-  /* The expression entered by the user.  */
-  const char *expression;
-
-  /* The resulting PC expression derived from evaluating EXPRESSION.  */
-  CORE_ADDR expr_pc;
-
-  /* Any specified file symtabs.  */
-
-  /* The user-supplied source filename or NULL if none was specified.  */
-  const char *source_filename;
+  /* An explicit location describing the SaLs.  */
+  struct explicit_location explicit;
 
   /* The list of symtabs to search to which to limit the search.  May not
-     be NULL.  If SOURCE_FILENAME is NULL (no user-specified filename),
-     FILE_SYMTABS should contain one single NULL member.  This will
-     cause the code to use the default symtab.  */
+     be NULL.  If explicit.SOURCE_FILENAME is NULL (no user-specified
+     filename), FILE_SYMTABS should contain one single NULL member.  This
+     will cause the code to use the default symtab.  */
   VEC (symtab_ptr) *file_symtabs;
 
-  /* The name of a function or method and any matching symbols.  */
-
-  /* The user-specified function name.  If no function name was
-     supplied, this may be NULL.  */
-  const char *function_name;
-
   /* A list of matching function symbols and minimal symbols.  Both lists
      may be NULL if no matching symbols were found.  */
   VEC (symbolp) *function_symbols;
   VEC (bound_minimal_symbol_d) *minimal_symbols;
 
-  /* The name of a label and matching symbols.  */
-
-  /* The user-specified label name.  */
-  const char *label_name;
-
   /* A structure of matching label symbols and the corresponding
      function symbol in which the label was found.  Both may be NULL
      or both must be non-NULL.  */
@@ -140,10 +93,6 @@ struct linespec
     VEC (symbolp) *label_symbols;
     VEC (symbolp) *function_symbols;
   } labels;
-
-  /* Line offset.  It may be LINE_OFFSET_UNKNOWN, meaning that no
-   offset was specified.  */
-  struct line_offset line_offset;
 };
 typedef struct linespec *linespec_p;
 
@@ -196,6 +145,9 @@ struct linespec_state
   /* This is a set of address_entry objects which is used to prevent
      duplicate symbols from being entered into the result.  */
   htab_t addr_set;
+
+  /* Are we building a linespec?  */
+  int is_linespec;
 };
 
 /* This is a helper object that is used when collecting symbols into a
@@ -302,6 +254,10 @@ struct ls_parser
 };
 typedef struct ls_parser linespec_parser;
 
+/* A convenience macro for accessing the explicit location result of
+   the parser.  */
+#define PARSER_EXPLICIT(PPTR) (&PARSER_RESULT ((PPTR))->explicit)
+
 /* Prototypes for local functions.  */
 
 static void iterate_over_file_blocks (struct symtab *symtab,
@@ -1572,6 +1528,29 @@ unexpected_linespec_error (linespec_parser *parser)
 		 token_type_strings[token.type]);
 }
 
+/* Throw an undefined label error.  */
+
+static void ATTRIBUTE_NORETURN
+undefined_label_error (const char *function, const char *label)
+{
+  if (function != NULL)
+    throw_error (NOT_FOUND_ERROR,
+                _("No label \"%s\" defined in function \"%s\"."),
+                label, function);
+  else
+    throw_error (NOT_FOUND_ERROR,
+                _("No label \"%s\" defined in current function."),
+                label);
+}
+
+/* Throw a source file not found error.  */
+
+static void ATTRIBUTE_NORETURN
+source_file_not_found_error (const char *name)
+{
+  throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
+}
+
 /* Parse and return a line offset in STRING.  */
 
 static struct line_offset
@@ -1618,7 +1597,7 @@ linespec_parse_basic (linespec_parser *parser)
       /* Record the line offset and get the next token.  */
       name = copy_token_string (token);
       cleanup = make_cleanup (xfree, name);
-      PARSER_RESULT (parser)->line_offset = linespec_parse_line_offset (name);
+      PARSER_EXPLICIT (parser)->line_offset = linespec_parse_line_offset (name);
       do_cleanups (cleanup);
 
       /* Get the next token.  */
@@ -1655,7 +1634,7 @@ linespec_parse_basic (linespec_parser *parser)
     {
       PARSER_RESULT (parser)->function_symbols = symbols;
       PARSER_RESULT (parser)->minimal_symbols = minimal_symbols;
-      PARSER_RESULT (parser)->function_name = name;
+      PARSER_EXPLICIT (parser)->function_name = name;
       symbols = NULL;
       discard_cleanups (cleanup);
     }
@@ -1669,7 +1648,7 @@ linespec_parse_basic (linespec_parser *parser)
 	{
 	  PARSER_RESULT (parser)->labels.label_symbols = labels;
 	  PARSER_RESULT (parser)->labels.function_symbols = symbols;
-	  PARSER_RESULT (parser)->label_name = name;
+	  PARSER_EXPLICIT (parser)->label_name = name;
 	  symbols = NULL;
 	  discard_cleanups (cleanup);
 	}
@@ -1677,14 +1656,14 @@ linespec_parse_basic (linespec_parser *parser)
 	       && *LS_TOKEN_STOKEN (token).ptr == '$')
 	{
 	  /* User specified a convenience variable or history value.  */
-	  PARSER_RESULT (parser)->line_offset
+	  PARSER_EXPLICIT (parser)->line_offset
 	    = linespec_parse_variable (PARSER_STATE (parser), name);
 
-	  if (PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
+	  if (PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
 	    {
 	      /* The user-specified variable was not valid.  Do not
 		 throw an error here.  parse_linespec will do it for us.  */
-	      PARSER_RESULT (parser)->function_name = name;
+	      PARSER_EXPLICIT (parser)->function_name = name;
 	      discard_cleanups (cleanup);
 	      return;
 	    }
@@ -1699,7 +1678,7 @@ linespec_parse_basic (linespec_parser *parser)
 	     an error here.  parse_linespec will do it for us.  */
 
 	  /* Save a copy of the name we were trying to lookup.  */
-	  PARSER_RESULT (parser)->function_name = name;
+	  PARSER_EXPLICIT (parser)->function_name = name;
 	  discard_cleanups (cleanup);
 	  return;
 	}
@@ -1719,7 +1698,7 @@ linespec_parse_basic (linespec_parser *parser)
 	     get the next token.  */
 	  name = copy_token_string (token);
 	  cleanup = make_cleanup (xfree, name);
-	  PARSER_RESULT (parser)->line_offset
+	  PARSER_EXPLICIT (parser)->line_offset
 	    = linespec_parse_line_offset (name);
 	  do_cleanups (cleanup);
 
@@ -1739,16 +1718,15 @@ linespec_parse_basic (linespec_parser *parser)
 	    {
 	      PARSER_RESULT (parser)->labels.label_symbols = labels;
 	      PARSER_RESULT (parser)->labels.function_symbols = symbols;
-	      PARSER_RESULT (parser)->label_name = name;
+	      PARSER_EXPLICIT (parser)->label_name = name;
 	      symbols = NULL;
 	      discard_cleanups (cleanup);
 	    }
 	  else
 	    {
 	      /* We don't know what it was, but it isn't a label.  */
-	      throw_error (NOT_FOUND_ERROR,
-			   _("No label \"%s\" defined in function \"%s\"."),
-			   name, PARSER_RESULT (parser)->function_name);
+	      undefined_label_error (PARSER_EXPLICIT (parser)->function_name,
+				     name);
 	    }
 
 	  /* Check for a line offset.  */
@@ -1766,7 +1744,7 @@ linespec_parse_basic (linespec_parser *parser)
 	      name = copy_token_string (token);
 	      cleanup = make_cleanup (xfree, name);
 
-	      PARSER_RESULT (parser)->line_offset
+	      PARSER_EXPLICIT (parser)->line_offset
 		= linespec_parse_line_offset (name);
 	      do_cleanups (cleanup);
 
@@ -1783,43 +1761,28 @@ linespec_parse_basic (linespec_parser *parser)
 }
 
 /* Canonicalize the linespec contained in LS.  The result is saved into
-   STATE->canonical.  */
+   STATE->canonical.  This function handles both linespec and explicit
+   locations.  */
 
 static void
 canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 {
-  char *tmp;
-  struct ui_file *buf;
-  int need_colon = 0;
-  struct cleanup *cleanup;
+  struct event_location *canon;
+  struct explicit_location *explicit;
 
   /* If canonicalization was not requested, no need to do anything.  */
   if (!state->canonical)
     return;
 
-  buf = mem_fileopen ();
-  cleanup = make_cleanup_ui_file_delete (buf);
-
-  if (ls->source_filename)
-    {
-      fputs_unfiltered (ls->source_filename, buf);
-      need_colon = 1;
-    }
-
-  if (ls->function_name)
-    {
-      if (need_colon)
-	fputc_unfiltered (':', buf);
-      fputs_unfiltered (ls->function_name, buf);
-      need_colon = 1;
-    }
+  /* Save everything as an explicit location.  */
+  canon = state->canonical->location = new_explicit_location (&ls->explicit);
+  explicit = get_explicit_location (canon);
 
-  if (ls->label_name)
+  if (explicit->label_name != NULL)
     {
-      if (need_colon)
-	fputc_unfiltered (':', buf);
+      state->canonical->special_display = 1;
 
-      if (ls->function_name == NULL)
+      if (explicit->function_name == NULL)
 	{
 	  struct symbol *s;
 
@@ -1828,30 +1791,17 @@ canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 		      && (VEC_length (symbolp, ls->labels.function_symbols)
 			  == 1));
 	  s = VEC_index (symbolp, ls->labels.function_symbols, 0);
-	  fputs_unfiltered (SYMBOL_NATURAL_NAME (s), buf);
-	  fputc_unfiltered (':', buf);
+	  explicit->function_name = xstrdup (SYMBOL_NATURAL_NAME (s));
 	}
-
-      fputs_unfiltered (ls->label_name, buf);
-      need_colon = 1;
-      state->canonical->special_display = 1;
     }
 
-  if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
+  /* If this location originally came from a linespec, save a string
+     representation of it for display and saving to file.  */
+  if (state->is_linespec)
     {
-      if (need_colon)
-	fputc_unfiltered (':', buf);
-      fprintf_filtered (buf, "%s%d",
-			(ls->line_offset.sign == LINE_OFFSET_NONE ? ""
-			 : (ls->line_offset.sign
-			    == LINE_OFFSET_PLUS ? "+" : "-")),
-			ls->line_offset.offset);
+      set_event_location_string (canon,
+				 explicit_location_to_linespec (explicit));
     }
-
-  tmp = ui_file_xstrdup (buf, NULL);
-  make_cleanup (xfree, tmp);
-  state->canonical->location = new_linespec_location (&tmp);
-  do_cleanups (cleanup);
 }
 
 /* Given a line offset in LS, construct the relevant SALs.  */
@@ -1891,18 +1841,18 @@ create_sals_line_offset (struct linespec_state *self,
       use_default = 1;
     }
 
-  val.line = ls->line_offset.offset;
-  switch (ls->line_offset.sign)
+  val.line = ls->explicit.line_offset.offset;
+  switch (ls->explicit.line_offset.sign)
     {
     case LINE_OFFSET_PLUS:
-      if (ls->line_offset.offset == 0)
+      if (ls->explicit.line_offset.offset == 0)
 	val.line = 5;
       if (use_default)
 	val.line = self->default_line + val.line;
       break;
 
     case LINE_OFFSET_MINUS:
-      if (ls->line_offset.offset == 0)
+      if (ls->explicit.line_offset.offset == 0)
 	val.line = 15;
       if (use_default)
 	val.line = self->default_line - val.line;
@@ -1994,9 +1944,9 @@ create_sals_line_offset (struct linespec_state *self,
 
   if (values.nelts == 0)
     {
-      if (ls->source_filename)
+      if (ls->explicit.source_filename)
 	throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
-		     val.line, ls->source_filename);
+		     val.line, ls->explicit.source_filename);
       else
 	throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
 		     val.line);
@@ -2093,13 +2043,13 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 	    }
 	}
     }
-  else if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
+  else if (ls->explicit.line_offset.sign != LINE_OFFSET_UNKNOWN)
     {
       /* Only an offset was specified.  */
 	sals = create_sals_line_offset (state, ls);
 
 	/* Make sure we have a filename for canonicalization.  */
-	if (ls->source_filename == NULL)
+	if (ls->explicit.source_filename == NULL)
 	  {
 	    const char *fullname = symtab_to_fullname (state->default_symtab);
 
@@ -2107,7 +2057,7 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 	       form so that displaying SOURCE_FILENAME can follow the current
 	       FILENAME_DISPLAY_STRING setting.  But as it is used only rarely
 	       it has been kept for code simplicity only in absolute form.  */
-	    ls->source_filename = xstrdup (fullname);
+	    ls->explicit.source_filename = xstrdup (fullname);
 	  }
     }
   else
@@ -2124,6 +2074,72 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
   return sals;
 }
 
+/* Convert the explicit location EXPLICIT into SaLs.  */
+
+static struct symtabs_and_lines
+convert_explicit_location_to_sals (struct linespec_state *self,
+				   linespec_p result,
+				   const struct explicit_location *explicit)
+{
+  VEC (symbolp) *symbols, *labels;
+  VEC (bound_minimal_symbol_d) *minimal_symbols;
+
+  if (explicit->source_filename != NULL)
+    {
+      TRY
+	{
+	  result->file_symtabs
+	    = symtabs_from_filename (explicit->source_filename);
+	}
+      CATCH (except, RETURN_MASK_ERROR)
+	{
+	  source_file_not_found_error (explicit->source_filename);
+	}
+      END_CATCH
+      result->explicit.source_filename = xstrdup (explicit->source_filename);
+    }
+  else
+    {
+      /* A NULL entry means to use the default symtab.  */
+      VEC_safe_push (symtab_ptr, result->file_symtabs, NULL);
+    }
+
+  if (explicit->function_name != NULL)
+    {
+      find_linespec_symbols (self, result->file_symtabs,
+			     explicit->function_name, &symbols,
+			     &minimal_symbols);
+
+      if (symbols == NULL && minimal_symbols == NULL)
+	symbol_not_found_error (explicit->function_name,
+				result->explicit.source_filename);
+
+      result->explicit.function_name = xstrdup (explicit->function_name);
+      result->function_symbols = symbols;
+      result->minimal_symbols = minimal_symbols;
+    }
+
+  if (explicit->label_name != NULL)
+    {
+      symbols = NULL;
+      labels = find_label_symbols (self, result->function_symbols,
+				   &symbols, explicit->label_name);
+
+      if (labels == NULL)
+	undefined_label_error (result->explicit.function_name,
+			       explicit->label_name);
+
+      result->explicit.label_name = xstrdup (explicit->label_name);
+      result->labels.label_symbols = labels;
+      result->labels.function_symbols = symbols;
+    }
+
+  if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+    result->explicit.line_offset = explicit->line_offset;
+
+   return convert_linespec_to_sals (self, result);
+}
+
 /* Parse a string that specifies a linespec.
 
    The basic grammar of linespecs:
@@ -2229,13 +2245,13 @@ parse_linespec (linespec_parser *parser, const char *arg)
       /* User specified a convenience variable or history value.  */
       var = copy_token_string (token);
       cleanup = make_cleanup (xfree, var);
-      PARSER_RESULT (parser)->line_offset
+      PARSER_EXPLICIT (parser)->line_offset
 	= linespec_parse_variable (PARSER_STATE (parser), var);
       do_cleanups (cleanup);
 
       /* If a line_offset wasn't found (VAR is the name of a user
 	 variable/function), then skip to normal symbol processing.  */
-      if (PARSER_RESULT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
+      if (PARSER_EXPLICIT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
 	{
 	  /* Consume this token.  */
 	  linespec_lexer_consume_token (parser);
@@ -2273,7 +2289,7 @@ parse_linespec (linespec_parser *parser, const char *arg)
       if (file_exception.reason >= 0)
 	{
 	  /* Symtabs were found for the file.  Record the filename.  */
-	  PARSER_RESULT (parser)->source_filename = user_filename;
+	  PARSER_EXPLICIT (parser)->source_filename = user_filename;
 
 	  /* Get the next token.  */
 	  token = linespec_lexer_consume_token (parser);
@@ -2310,7 +2326,7 @@ parse_linespec (linespec_parser *parser, const char *arg)
 
   if (PARSER_RESULT (parser)->function_symbols == NULL
       && PARSER_RESULT (parser)->labels.label_symbols == NULL
-      && PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
+      && PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
       && PARSER_RESULT (parser)->minimal_symbols == NULL)
     {
       /* The linespec didn't parse.  Re-throw the file exception if
@@ -2319,8 +2335,8 @@ parse_linespec (linespec_parser *parser, const char *arg)
 	throw_exception (file_exception);
 
       /* Otherwise, the symbol is not found.  */
-      symbol_not_found_error (PARSER_RESULT (parser)->function_name,
-			      PARSER_RESULT (parser)->source_filename);
+      symbol_not_found_error (PARSER_EXPLICIT (parser)->function_name,
+			      PARSER_EXPLICIT (parser)->source_filename);
     }
 
  convert_to_sals:
@@ -2358,6 +2374,7 @@ linespec_state_constructor (struct linespec_state *self,
   self->program_space = current_program_space;
   self->addr_set = htab_create_alloc (10, hash_address_entry, eq_address_entry,
 				      xfree, xcalloc, xfree);
+  self->is_linespec = 0;
 }
 
 /* Initialize a new linespec parser.  */
@@ -2372,7 +2389,7 @@ linespec_parser_new (linespec_parser *parser,
   memset (parser, 0, sizeof (linespec_parser));
   parser->lexer.current.type = LSTOKEN_CONSUMED;
   memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
-  PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
+  PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
   linespec_state_constructor (PARSER_STATE (parser), flags, language,
 			      default_symtab, default_line, canonical);
 }
@@ -2392,10 +2409,9 @@ linespec_parser_delete (void *arg)
 {
   linespec_parser *parser = (linespec_parser *) arg;
 
-  xfree ((char *) PARSER_RESULT (parser)->expression);
-  xfree ((char *) PARSER_RESULT (parser)->source_filename);
-  xfree ((char *) PARSER_RESULT (parser)->label_name);
-  xfree ((char *) PARSER_RESULT (parser)->function_name);
+  xfree (PARSER_EXPLICIT (parser)->source_filename);
+  xfree (PARSER_EXPLICIT (parser)->label_name);
+  xfree (PARSER_EXPLICIT (parser)->function_name);
 
   if (PARSER_RESULT (parser)->file_symtabs != NULL)
     VEC_free (symtab_ptr, PARSER_RESULT (parser)->file_symtabs);
@@ -2468,6 +2484,7 @@ event_location_to_sals (linespec_parser *parser,
     {
     case LINESPEC_LOCATION:
       {
+	PARSER_STATE (parser)->is_linespec = 1;
 	TRY
 	  {
 	    result = parse_linespec (parser, get_linespec_location (location));
@@ -2486,6 +2503,17 @@ event_location_to_sals (linespec_parser *parser,
 					    get_address_location (location));
       break;
 
+    case EXPLICIT_LOCATION:
+      {
+	const struct explicit_location *explicit;
+
+	explicit = get_explicit_location_const (location);
+	result = convert_explicit_location_to_sals (PARSER_STATE (parser),
+						    PARSER_RESULT (parser),
+						    explicit);
+      }
+      break;
+
     case PROBE_LOCATION:
       /* Probes are handled by their own decoders.  */
       gdb_assert_not_reached ("attempt to decode probe location");
@@ -2735,7 +2763,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
       memcpy (saved_arg, arg, new_argptr - arg);
       saved_arg[new_argptr - arg] = '\0';
 
-      ls->function_name = xstrdup (saved_arg);
+      ls->explicit.function_name = xstrdup (saved_arg);
       ls->function_symbols = info.result.symbols;
       ls->minimal_symbols = info.result.minimal_symbols;
       values = convert_linespec_to_sals (self, ls);
@@ -2746,10 +2774,10 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
 
 	  self->canonical->pre_expanded = 1;
 
-	  if (ls->source_filename)
+	  if (ls->explicit.source_filename)
 	    {
 	      str = xstrprintf ("%s:%s",
-				ls->source_filename, saved_arg);
+				ls->explicit.source_filename, saved_arg);
 	    }
 	  else
 	    str = xstrdup (saved_arg);
@@ -3129,7 +3157,7 @@ symtabs_from_filename (const char *filename)
 	throw_error (NOT_FOUND_ERROR,
 		     _("No symbol table is loaded.  "
 		       "Use the \"file\" command."));
-      throw_error (NOT_FOUND_ERROR, _("No source file named %s."), filename);
+      source_file_not_found_error (filename);
     }
 
   return result;
diff --git a/gdb/location.c b/gdb/location.c
index 6059679..7882b2d 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -50,6 +50,10 @@ struct event_location
     /* An address in the inferior.  */
     CORE_ADDR address;
 #define EL_ADDRESS(PTR) (PTR)->u.address
+
+    /* An explicit location.  */
+    struct explicit_location explicit;
+#define EL_EXPLICIT(PTR) (&((PTR)->u.explicit))
   } u;
 
   /* Cached string representation of this location.  This is used, e.g., to
@@ -68,6 +72,15 @@ event_location_type (const struct event_location *location)
 
 /* See description in location.h.  */
 
+void
+initialize_explicit_location (struct explicit_location *explicit)
+{
+  memset (explicit, 0, sizeof (struct explicit_location));
+  explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
+}
+
+/* See description in location.h.  */
+
 struct event_location *
 new_linespec_location (char **linespec)
 {
@@ -145,6 +158,137 @@ get_probe_location (const struct event_location *location)
 /* See description in location.h.  */
 
 struct event_location *
+new_explicit_location (const struct explicit_location *explicit)
+{
+  struct event_location tmp;
+
+  memset (&tmp, 0, sizeof (struct event_location));
+  EL_TYPE (&tmp) = EXPLICIT_LOCATION;
+  initialize_explicit_location (EL_EXPLICIT (&tmp));
+  if (explicit != NULL)
+    {
+      if (explicit->source_filename != NULL)
+	{
+	  EL_EXPLICIT (&tmp)->source_filename
+	    = explicit->source_filename;
+	}
+
+      if (explicit->function_name != NULL)
+	EL_EXPLICIT (&tmp)->function_name
+	  = explicit->function_name;
+
+      if (explicit->label_name != NULL)
+	EL_EXPLICIT (&tmp)->label_name = explicit->label_name;
+
+      if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+	EL_EXPLICIT (&tmp)->line_offset = explicit->line_offset;
+    }
+
+  return copy_event_location (&tmp);
+}
+
+/* See description in location.h.  */
+
+struct explicit_location *
+get_explicit_location (struct event_location *location)
+{
+  gdb_assert (EL_TYPE (location) == EXPLICIT_LOCATION);
+  return EL_EXPLICIT (location);
+}
+
+/* See description in location.h.  */
+
+const struct explicit_location *
+get_explicit_location_const (const struct event_location *location)
+{
+  gdb_assert (EL_TYPE (location) == EXPLICIT_LOCATION);
+  return EL_EXPLICIT (location);
+}
+
+/* This convenience function returns a malloc'd string which
+   represents the location in EXPLICIT.
+
+   AS_LINESPEC is non-zero if this string should be a linespec.
+   Otherwise it will be output in explicit form.  */
+
+static char *
+explicit_to_string_internal (int as_linespec,
+			     const struct explicit_location *explicit)
+{
+  struct ui_file *buf;
+  char space, *result;
+  int need_space = 0;
+  struct cleanup *cleanup;
+
+  space = as_linespec ? ':' : ' ';
+  buf = mem_fileopen ();
+  cleanup = make_cleanup_ui_file_delete (buf);
+
+  if (explicit->source_filename != NULL)
+    {
+      if (!as_linespec)
+	fputs_unfiltered ("-source ", buf);
+      fputs_unfiltered (explicit->source_filename, buf);
+      need_space = 1;
+    }
+
+  if (explicit->function_name != NULL)
+    {
+      if (need_space)
+	fputc_unfiltered (space, buf);
+      if (!as_linespec)
+	fputs_unfiltered ("-function ", buf);
+      fputs_unfiltered (explicit->function_name, buf);
+      need_space = 1;
+    }
+
+  if (explicit->label_name != NULL)
+    {
+      if (need_space)
+	fputc_unfiltered (space, buf);
+      if (!as_linespec)
+	fputs_unfiltered ("-label ", buf);
+      fputs_unfiltered (explicit->label_name, buf);
+      need_space = 1;
+    }
+
+  if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+    {
+      if (need_space)
+	fputc_unfiltered (space, buf);
+      if (!as_linespec)
+	fputs_unfiltered ("-line ", buf);
+      fprintf_filtered (buf, "%s%d",
+			(explicit->line_offset.sign == LINE_OFFSET_NONE ? ""
+			 : (explicit->line_offset.sign
+			    == LINE_OFFSET_PLUS ? "+" : "-")),
+			explicit->line_offset.offset);
+    }
+
+  result = ui_file_xstrdup (buf, NULL);
+  do_cleanups (cleanup);
+  return result;
+}
+
+/* See description in location.h.  */
+
+char *
+explicit_location_to_string (const struct explicit_location *explicit)
+{
+  return explicit_to_string_internal (0, explicit);
+}
+
+/* See description in location.h.  */
+
+char *
+explicit_location_to_linespec (const struct explicit_location *explicit)
+{
+  return explicit_to_string_internal (1, explicit);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
 copy_event_location (const struct event_location *src)
 {
   struct event_location *dst;
@@ -165,6 +309,22 @@ copy_event_location (const struct event_location *src)
       EL_ADDRESS (dst) = EL_ADDRESS (src);
       break;
 
+    case EXPLICIT_LOCATION:
+      if (EL_EXPLICIT (src)->source_filename != NULL)
+	EL_EXPLICIT (dst)->source_filename
+	  = xstrdup (EL_EXPLICIT (src)->source_filename);
+
+      if (EL_EXPLICIT (src)->function_name != NULL)
+	EL_EXPLICIT (dst)->function_name
+	  = xstrdup (EL_EXPLICIT (src)->function_name);
+
+      if (EL_EXPLICIT (src)->label_name != NULL)
+	EL_EXPLICIT (dst)->label_name = xstrdup (EL_EXPLICIT (src)->label_name);
+
+      EL_EXPLICIT (dst)->line_offset = EL_EXPLICIT (src)->line_offset;
+      break;
+
+
     case PROBE_LOCATION:
       if (EL_PROBE (src) != NULL)
 	EL_PROBE (dst) = xstrdup (EL_PROBE (src));
@@ -214,6 +374,12 @@ delete_event_location (struct event_location *location)
 	  /* Nothing to do.  */
 	  break;
 
+	case EXPLICIT_LOCATION:
+	  xfree (EL_EXPLICIT (location)->source_filename);
+	  xfree (EL_EXPLICIT (location)->function_name);
+	  xfree (EL_EXPLICIT (location)->label_name);
+	  break;
+
 	case PROBE_LOCATION:
 	  xfree (EL_PROBE (location));
 	  break;
@@ -249,6 +415,10 @@ event_location_to_string_const (const struct event_location *location)
 		      core_addr_to_string (EL_ADDRESS (location)));
       break;
 
+    case EXPLICIT_LOCATION:
+      result = explicit_location_to_string (EL_EXPLICIT (location));
+      break;
+
     case PROBE_LOCATION:
       result = xstrdup (EL_PROBE (location));
       break;
@@ -326,6 +496,14 @@ event_location_empty_p (const struct event_location *location)
     case ADDRESS_LOCATION:
       return 0;
 
+    case EXPLICIT_LOCATION:
+      return (EL_EXPLICIT (location) == NULL
+	      || (EL_EXPLICIT (location)->source_filename == NULL
+		  && EL_EXPLICIT (location)->function_name == NULL
+		  && EL_EXPLICIT (location)->label_name == NULL
+		  && (EL_EXPLICIT (location)->line_offset.sign
+		      == LINE_OFFSET_UNKNOWN)));
+
     case PROBE_LOCATION:
       return EL_PROBE (location) == NULL;
 
diff --git a/gdb/location.h b/gdb/location.h
index 3112d63..fba1c17 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -22,6 +22,32 @@
 struct language_defn;
 struct event_location;
 
+/* An enumeration of possible signs for a line offset.  */
+
+enum offset_relative_sign
+{
+  /* No sign  */
+  LINE_OFFSET_NONE,
+
+  /* A plus sign ("+")  */
+  LINE_OFFSET_PLUS,
+
+  /* A minus sign ("-")  */
+  LINE_OFFSET_MINUS,
+
+  /* A special "sign" for unspecified offset.  */
+  LINE_OFFSET_UNKNOWN
+};
+
+/* A line offset in a location.  */
+
+struct line_offset
+{
+  /* Line offset and any specified sign.  */
+  int offset;
+  enum offset_relative_sign sign;
+};
+
 /* An enumeration of the various ways to specify a stop event
    location (used with create_breakpoint).  */
 
@@ -33,15 +59,52 @@ enum event_location_type
   /* An address in the inferior.  */
   ADDRESS_LOCATION,
 
+  /* An explicit location.  */
+  EXPLICIT_LOCATION,
+
   /* A probe location.  */
   PROBE_LOCATION
 };
 
+/* An explicit location.  This structure is used to bypass the
+   parsing done on linespecs.  It still has the same requirements
+   as linespecs, though.  For example, source_filename requires
+   at least one other field.  */
+
+struct explicit_location
+{
+  /* The source filename. Malloc'd.  */
+  char *source_filename;
+
+  /* The function name.  Malloc'd.  */
+  char *function_name;
+
+  /* The name of a label.  Malloc'd.  */
+  char *label_name;
+
+  /* A line offset relative to the start of the symbol
+     identified by the above fields or the current symtab
+     if the other fields are NULL.  */
+  struct line_offset line_offset;
+};
+
 /* Return the type of the given event location.  */
 
 extern enum event_location_type
   event_location_type (const struct event_location *);
 
+/* Return a malloc'd explicit string representation of the given
+   explicit location.  The location must already be canonicalized/valid.  */
+
+extern char *
+  explicit_location_to_string (const struct explicit_location *explicit);
+
+/* Return a malloc'd linespec string representation of the given
+   explicit location.  The location must already be canonicalized/valid.  */
+
+extern char *
+  explicit_location_to_linespec (const struct explicit_location *explicit);
+
 /* Return a string representation of the LOCATION.
    This function may return NULL for unspecified linespecs,
    e.g, LOCATION_LINESPEC and addr_string is NULL.
@@ -94,6 +157,26 @@ extern struct event_location *
 extern const char *
   get_probe_location (const struct event_location *location);
 
+/* Create a new explicit location.  If not NULL, EXPLICIT is checked for
+   validity.  If invalid, an exception is thrown.
+
+   The return result is malloc'd and should be freed with
+   delete_event_location.  */
+
+extern struct event_location *
+  new_explicit_location (const struct explicit_location *explicit);
+
+/* Return the explicit location of the given event_location
+   (which must be of type EXPLICIT_LOCATION).  */
+
+extern struct explicit_location *
+  get_explicit_location (struct event_location *location);
+
+/* A const version of the above.  */
+
+extern const struct explicit_location *
+  get_explicit_location_const (const struct event_location *location);
+
 /* Free an event location and any associated data.  */
 
 extern void delete_event_location (struct event_location *location);
@@ -108,12 +191,9 @@ extern struct cleanup *
 extern struct event_location *
   copy_event_location (const struct event_location *src);
 
-/* Allocate and "copy" the opaque struct event_location.  This is used
-   when decoding locations which must parse their inputs.  The return result
-   should be freed.  */
+/* Initialize the given explicit location.  */
 
-extern struct event_location *
-  copy_event_location_tmp (const struct event_location *src);
+extern void initialize_explicit_location (struct explicit_location *explicit);
 
 /* Attempt to convert the input string in *ARGP into an event location.
    ARGP is advanced past any processed input.  Returns a event_location

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 7/9] Explicit locations: add UI features for CLI
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (2 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 8/9] Explicit locations: MI support for " Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  6:55   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 5/9] Explicit locations: introduce probe locations Keith Seitz
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch exposes explicit locations to the CLI user.  This enables
users to "explicitly" specify attributes of the breakpoint location
to avoid any ambiguity that might otherwise exist with linespecs.

The general syntax of explicit locations is:
-source SOURCE_FILENAME -line {+-}LINE -function FUNCTION_NAME
-label LABEL_NAME

Option names may be abbreviated, e.g., "-s SOURCE_FILENAME -li 3" and users
may use the completer with either options or values.

gdb/ChangeLog:

	* completer.c: Include location.h.
	(enum match_type): New enum.
	(location_completer): Rename to ...
	(linespec_completer): ... this.
	(collect_explicit_location_matches, backup_text_ptr)
	(explicit_location_completer): New functions.
	(location_completer): "New" function; handle linespec
	and explicit location completions.
	(complete_line_internal): Remove all location completer-specific
	handling.
	* linespec.c (linespec_lexer_lex_keyword): Export.
	(is_ada_operator): Ditto.
	(find_toplevel_char): Ditto.
	(linespec_parse_line_offset): Ditto.
	Issue error if STRING is not numerical.
	(gdb_get_linespec_parser_quote_characters): New function.
	* linespec.h (linespec_parse_line_offset): Declare.
	(get_gdb_linespec_parser_quote_characters): Declare.
	(is_ada_operator): Declare.
	(find_toplevel_char): Declare.
	(linespec_lexer_lex_keyword): Declare.
	* location.c (explicit_to_event_location): New function.
	(explicit_location_lex_one): New function.
	(string_to_explicit_location): New function.
	(string_to_event_location): Handle explicit locations.
	* location.h (explicit_to_event_location): Declare.
	(string_to_explicit_location): Declare.

gdb/testsuite/ChangeLog:

	* gdb.linespec/3explicit.c: New file.
	* gdb.linespec/cpexplicit.cc: New file.
	* gdb.linespec/cpexplicit.exp: New file.
	* gdb.linespec/explicit.c: New file.
	* gdb.linespec/explicit.exp: New file.
	* gdb.linespec/explicit2.c: New file.
	* gdb.linespec/ls-errs.exp: Add explicit location tests.
---
 gdb/completer.c                           |  219 +++++++++++++++-
 gdb/linespec.c                            |   25 +-
 gdb/linespec.h                            |   20 +
 gdb/location.c                            |  215 ++++++++++++++++
 gdb/location.h                            |   15 +
 gdb/testsuite/gdb.linespec/3explicit.c    |   28 ++
 gdb/testsuite/gdb.linespec/cpexplicit.cc  |   63 +++++
 gdb/testsuite/gdb.linespec/cpexplicit.exp |  112 ++++++++
 gdb/testsuite/gdb.linespec/explicit.c     |   56 ++++
 gdb/testsuite/gdb.linespec/explicit.exp   |  393 +++++++++++++++++++++++++++++
 gdb/testsuite/gdb.linespec/explicit2.c    |   24 ++
 gdb/testsuite/gdb.linespec/ls-errs.exp    |   45 +++
 12 files changed, 1175 insertions(+), 40 deletions(-)
 create mode 100644 gdb/testsuite/gdb.linespec/3explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit2.c

diff --git a/gdb/completer.c b/gdb/completer.c
index c8c0e4c..b9ae591 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -26,6 +26,7 @@
 #include "target.h"
 #include "reggroups.h"
 #include "user-regs.h"
+#include "location.h"
 
 #include "cli/cli-decode.h"
 
@@ -42,6 +43,21 @@
 
 #include "completer.h"
 
+/* An enumeration of the various things a user might
+   attempt to complete for a location.  */
+
+enum explicit_location_match_type
+{
+    /* The filename of a source file.  */
+    MATCH_SOURCE,
+
+    /* The name of a function or method.  */
+    MATCH_FUNCTION,
+
+    /* The name of a label.  */
+    MATCH_LABEL
+};
+
 /* Prototypes for local functions.  */
 static
 char *line_completion_function (const char *text, int matches, 
@@ -174,7 +190,7 @@ filename_completer (struct cmd_list_element *ignore,
   return return_val;
 }
 
-/* Complete on locations, which might be of two possible forms:
+/* Complete on linespecs, which might be of two possible forms:
 
        file:line
    or
@@ -183,9 +199,9 @@ filename_completer (struct cmd_list_element *ignore,
    This is intended to be used in commands that set breakpoints
    etc.  */
 
-VEC (char_ptr) *
-location_completer (struct cmd_list_element *ignore, 
-		    const char *text, const char *word)
+static VEC (char_ptr) *
+linespec_location_completer (struct cmd_list_element *ignore,
+			     const char *text, const char *word)
 {
   int n_syms, n_files, ix;
   VEC (char_ptr) *fn_list = NULL;
@@ -332,6 +348,183 @@ location_completer (struct cmd_list_element *ignore,
   return list;
 }
 
+/* A helper function to collect explicit location matches for the given
+   LOCATION, which is attempting to match on WORD.  */
+
+static VEC (char_ptr) *
+collect_explicit_location_matches (struct event_location *location,
+				   enum explicit_location_match_type what,
+				   const char *word)
+{
+  VEC (char_ptr) *matches = NULL;
+  const struct explicit_location *explicit = get_explicit_location (location);
+
+  switch (what)
+    {
+    case MATCH_SOURCE:
+      {
+	const char *text = (explicit->source_filename == NULL
+			    ? "" : explicit->source_filename);
+
+	matches = make_source_files_completion_list (text, word);
+      }
+      break;
+
+    case MATCH_FUNCTION:
+      {
+	const char *text = (explicit->function_name == NULL
+			    ? "" : explicit->function_name);
+
+	if (explicit->source_filename != NULL)
+	  {
+	    matches
+	      = make_file_symbol_completion_list (text, word,
+						  explicit->source_filename);
+	  }
+	else
+	  matches = make_symbol_completion_list (text, word);
+      }
+      break;
+
+    case MATCH_LABEL:
+      /* Not supported.  */
+      break;
+
+    default:
+      gdb_assert_not_reached ("unhandled explicit_location_match_type");
+    }
+
+  return matches;
+}
+
+/* A convenience macro to (safely) back up P to the previous word.  */
+
+static const char *
+backup_text_ptr (const char *p, const char *text)
+{
+  while (p > text && isspace (*p))
+    --p;
+  for (; p > text && !isspace (p[-1]); --p)
+    ;
+
+  return p;
+}
+
+/* A completer function for explicit locations.  This function
+   completes both options ("-source", "-line", etc) and values.  */
+
+static VEC (char_ptr) *
+explicit_location_completer (struct cmd_list_element *ignore,
+			     struct event_location *location,
+			     const char *text, const char *word)
+{
+  const char *p;
+  VEC (char_ptr) *matches = NULL;
+
+  /* Find the beginning of the word.  This is necessary because
+     we need to know if we are completing an option name or value.  We
+     don't get the leading '-' from the completer.  */
+  p = backup_text_ptr (word, text);
+
+  if (*p == '-')
+    {
+      size_t len = strlen (word);
+
+      /* Completing on option name.  */
+
+      /* Skip over the '-'.  */
+      ++p;
+
+      if (strncmp (p, "source", len) == 0)
+	VEC_safe_push (char_ptr, matches, xstrdup ("source"));
+      if (strncmp (p, "function", len) == 0)
+	VEC_safe_push (char_ptr, matches, xstrdup ("function"));
+      if (strncmp (p, "line", len) == 0)
+	VEC_safe_push (char_ptr, matches, xstrdup ("line"));
+      if (strncmp (p, "label", len) == 0)
+	VEC_safe_push (char_ptr, matches, xstrdup ("label"));
+    }
+  else
+    {
+      /* Completing on value (or unknown).  Get the previous word to see what
+	 the user is completing on.  */
+      size_t len, offset;
+      const char *new_word, *end;
+      enum explicit_location_match_type what;
+      struct explicit_location *explicit = get_explicit_location (location);
+
+      /* Backup P to the previous word, which should be the option
+	 the user is attempting to complete.  */
+      offset = word - p;
+      end = --p;
+      p = backup_text_ptr (p, text);
+      len = end - p;
+
+      if (strncmp (p, "-source", len) == 0)
+	{
+	  what = MATCH_SOURCE;
+	  new_word = explicit->source_filename + offset;
+	}
+      else if (strncmp (p, "-function", len) == 0)
+	{
+	  what = MATCH_FUNCTION;
+	  new_word = explicit->function_name + offset;
+	}
+      else if (strncmp (p, "-label", len) == 0)
+	{
+	  what = MATCH_LABEL;
+	  new_word = explicit->label_name + offset;
+	}
+      else
+	{
+	  /* The user isn't completing on any valid option name,
+	     e.g., "break -source foo.c [tab]".  */
+	  return NULL;
+	}
+
+      /* If the user hasn't entered a search expression, e.g.,
+	 "break -function <TAB><TAB>", new_word will be NULL, but
+	 search routines require non-NULL search words.  */
+      if (new_word == NULL)
+	new_word = "";
+
+      /* Now gather matches  */
+      matches = collect_explicit_location_matches (location, what, new_word);
+    }
+
+  return matches;
+}
+
+/* A completer for locations.  */
+
+VEC (char_ptr) *
+location_completer (struct cmd_list_element *ignore,
+		    const char *text, const char *word)
+{
+  VEC (char_ptr) *matches = NULL;
+  const char *copy = text;
+  struct event_location *location;
+
+  location = string_to_explicit_location (&copy, current_language, 1);
+  if (location != NULL)
+    {
+      struct cleanup *cleanup;
+
+      cleanup = make_cleanup_delete_event_location (location);
+      matches = explicit_location_completer (ignore, location, text, word);
+      do_cleanups (cleanup);
+    }
+  else
+    {
+      /* This is an address or linespec location.
+	 Right now both of these are handled by the (old) linespec
+	 completer.  */
+      matches = linespec_location_completer (ignore, text, word);
+    }
+
+  return matches;
+}
+
 /* Helper for expression_completer which recursively adds field and
    method names from TYPE, a struct or union type, to the array
    OUTPUT.  */
@@ -687,16 +880,6 @@ complete_line_internal (const char *text,
 		      rl_completer_word_break_characters =
 			gdb_completer_file_name_break_characters;
 		    }
-		  else if (c->completer == location_completer)
-		    {
-		      /* Commands which complete on locations want to
-			 see the entire argument.  */
-		      for (p = word;
-			   p > tmp_command
-			     && p[-1] != ' ' && p[-1] != '\t';
-			   p--)
-			;
-		    }
 		  if (reason == handle_brkchars
 		      && c->completer_handle_brkchars != NULL)
 		    (*c->completer_handle_brkchars) (c, p, word);
@@ -765,14 +948,6 @@ complete_line_internal (const char *text,
 		  rl_completer_word_break_characters =
 		    gdb_completer_file_name_break_characters;
 		}
-	      else if (c->completer == location_completer)
-		{
-		  for (p = word;
-		       p > tmp_command
-			 && p[-1] != ' ' && p[-1] != '\t';
-		       p--)
-		    ;
-		}
 	      if (reason == handle_brkchars
 		  && c->completer_handle_brkchars != NULL)
 		(*c->completer_handle_brkchars) (c, p, word);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index a7e6248..3fe2dbd 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -323,8 +323,6 @@ static int compare_symbols (const void *a, const void *b);
 
 static int compare_msymbols (const void *a, const void *b);
 
-static const char *find_toplevel_char (const char *s, char c);
-
 /* Permitted quote characters for the parser.  This is different from the
    completer's quote characters to allow backward compatibility with the
    previous parser.  */
@@ -419,10 +417,9 @@ linespec_lexer_lex_keyword (const char *p)
   return NULL;
 }
 
-/* Does STRING represent an Ada operator?  If so, return the length
-   of the decoded operator name.  If not, return 0.  */
+/*  See description in linespec.h.  */
 
-static int
+int
 is_ada_operator (const char *string)
 {
   const struct ada_opname_map *mapping;
@@ -1140,7 +1137,7 @@ find_methods (struct type *t, const char *name,
    strings.  Also, ignore the char within a template name, like a ','
    within foo<int, int>.  */
 
-static const char *
+const char *
 find_toplevel_char (const char *s, char c)
 {
   int quoted = 0;		/* zero if we're not in quotes;
@@ -1551,11 +1548,12 @@ source_file_not_found_error (const char *name)
   throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
 }
 
-/* Parse and return a line offset in STRING.  */
+/* See description in linespec.h.  */
 
-static struct line_offset
+struct line_offset
 linespec_parse_line_offset (const char *string)
 {
+  const char *start = string;
   struct line_offset line_offset = {0, LINE_OFFSET_NONE};
 
   if (*string == '+')
@@ -1569,6 +1567,9 @@ linespec_parse_line_offset (const char *string)
       ++string;
     }
 
+  if (*string != '\0' && !isdigit (*string))
+    error (_("malformed line offset: \"%s\""), start);
+
   /* Right now, we only allow base 10 for offsets.  */
   line_offset.offset = atoi (string);
   return line_offset;
@@ -3890,3 +3891,11 @@ make_cleanup_destroy_linespec_result (struct linespec_result *ls)
 {
   return make_cleanup (cleanup_linespec_result, ls);
 }
+
+/* Return the quote characters permitted by the linespec parser.  */
+
+const char *
+get_gdb_linespec_parser_quote_characters (void)
+{
+  return linespec_quote_characters;
+}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 391ed26..2a76283 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -157,6 +157,26 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
 
 extern const char *linespec_lexer_lex_keyword (const char *p);
 
+/* Parse a line offset from STRING.  */
+
+extern struct line_offset linespec_parse_line_offset (const char *string);
+
+/* Return the quote characters permitted by the linespec parser.  */
+
+extern const char *get_gdb_linespec_parser_quote_characters (void);
+
+/* Does STRING represent an Ada operator?  If so, return the length
+   of the decoded operator name.  If not, return 0.  */
+
+extern int is_ada_operator (const char *string);
+
+/* Find an instance of the character C in the string S that is outside
+   of all parenthesis pairs, single-quoted strings, and double-quoted
+   strings.  Also, ignore the char within a template name, like a ','
+   within foo<int, int>.  */
+
+extern const char *find_toplevel_char (const char *s, char c);
+
 /* Find the end of the (first) linespec pointed to by *STRINGP.
    STRINGP will be advanced to this point.  */
 
diff --git a/gdb/location.c b/gdb/location.c
index 7882b2d..779bcfa 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -442,6 +442,203 @@ event_location_to_string (struct event_location *location)
   return EL_STRING (location);
 }
 
+/* A lexer for explicit locations.  This function will advance INP
+   past any strings that it lexes.  Returns a malloc'd copy of the
+   lexed string or NULL if no lexing was done.  */
+
+static char *
+explicit_location_lex_one (const char **inp,
+			   const struct language_defn *language)
+{
+  const char *start = *inp;
+
+  if (*start == '\0')
+    return NULL;
+
+  /* If quoted, skip to the ending quote.  */
+  if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
+    {
+      char quote_char = *start;
+
+      /* If the input is not an Ada operator, skip to the matching
+	 closing quote and return the string.  */
+      if (!(language->la_language == language_ada
+	    && quote_char == '\"' && is_ada_operator (start)))
+	{
+	  const char *end = find_toplevel_char (start + 1, quote_char);
+
+	  if (end == NULL)
+	    error (_("Unmatched quote, %s."), start);
+	  *inp = end + 1;
+	  return savestring (start + 1, *inp - start - 2);
+	}
+    }
+
+  /* If the input starts with '-' or '+', the string ends with the next
+     whitespace.  */
+  if (*start == '-' || *start == '+')
+    *inp = skip_to_space_const (*inp);
+  else
+    {
+      /* Handle numbers first, stopping at the next whitespace or ','.  */
+      while (isdigit (*inp[0]))
+	++(*inp);
+      if (*inp[0] == '\0' || isspace (*inp[0]) || *inp[0] == ',')
+	return savestring (start, *inp - start);
+
+      /* Otherwise stop at the next occurrence of "SPACE -", '\0',
+	 keyword, or ','.  */
+      *inp = start;
+      while ((*inp)[0]
+	     && (*inp)[0] != ','
+	     && !(isspace ((*inp)[0])
+		  && ((*inp)[1] == '-'
+		      || linespec_lexer_lex_keyword (&(*inp)[1]))))
+	{
+	  /* Special case: C++ operator,.  */
+	  if (language->la_language == language_cplus
+	      && strncmp (*inp, "operator", 8)
+	      && (*inp)[9] == ',')
+	    (*inp) += 9;
+	  ++(*inp);
+	}
+    }
+
+  if (*inp - start > 0)
+    return savestring (start, *inp - start);
+
+  return NULL;
+}
+
+/* See description in location.h.  */
+
+struct event_location *
+string_to_explicit_location (const char **argp,
+			     const struct language_defn *language,
+			     int dont_throw)
+{
+  struct cleanup *cleanup;
+  struct event_location *location;
+
+  /* It is assumed that input beginning with '-' and a non-digit
+     character is an explicit location.  */
+  if (argp == NULL
+      || *argp == '\0'
+      || *argp[0] != '-'
+      || !isalpha ((*argp)[1]))
+    return NULL;
+
+  location = new_explicit_location (NULL);
+  cleanup = make_cleanup_delete_event_location (location);
+
+  /* Process option/argument pairs.  dprintf_command
+     requires that processing stop on ','.  */
+  while ((*argp)[0] != '\0' && (*argp)[0] != ',')
+    {
+      int len;
+      char *opt, *oarg;
+      const char *start;
+      struct cleanup *inner;
+
+      /* If *ARGP starts with a keyword, stop processing
+	 options.  */
+      if (linespec_lexer_lex_keyword (*argp) != NULL)
+	break;
+
+      /* Mark the start of the string in case we need to rewind.  */
+      start = *argp;
+
+      /* Get the option string.  */
+      opt = explicit_location_lex_one (argp, language);
+      inner = make_cleanup (xfree, opt);
+
+      *argp = skip_spaces_const (*argp);
+
+      /* Get the argument string.  */
+      oarg = explicit_location_lex_one (argp, language);
+
+      *argp = skip_spaces_const (*argp);
+
+      /* Use the length of the option to allow abbreviations.  */
+      len = strlen (opt);
+
+      /* All options have a required argument.  Checking for this required
+	 argument is deferred until later.  */
+      if (strncmp (opt, "-source", len) == 0)
+	EL_EXPLICIT (location)->source_filename = oarg;
+      else if (strncmp (opt, "-function", len) == 0)
+	EL_EXPLICIT (location)->function_name = oarg;
+      else if (strncmp (opt, "-line", len) == 0)
+	{
+	  if (oarg != NULL)
+	    {
+	      TRY
+		{
+		  EL_EXPLICIT (location)->line_offset
+		    = linespec_parse_line_offset (oarg);
+		}
+	      CATCH (e, RETURN_MASK_ERROR)
+		{
+		  xfree (oarg);
+		  throw_exception (e);
+		}
+	      END_CATCH
+	      xfree (oarg);
+	      do_cleanups (inner);
+	      continue;
+	    }
+	}
+      else if (strncmp (opt, "-label", len) == 0)
+	EL_EXPLICIT (location)->label_name = oarg;
+      /* Only emit an "invalid argument" error for options
+	 that look like option strings.  */
+      else if (opt[0] == '-' && !isdigit (opt[1]))
+	{
+	  xfree (oarg);
+	  if (!dont_throw)
+	    error (_("invalid explicit location argument, \"%s\""), opt);
+	}
+      else
+	{
+	  /* End of the explicit location specification.
+	     Stop parsing and return whatever explicit location was
+	     parsed.  */
+	  *argp = start;
+	  xfree (oarg);
+	  do_cleanups (inner);
+	  discard_cleanups (cleanup);
+	  return location;
+	}
+
+      /* It's a little lame to error after the fact, but in this
+	 case, it provides a much better user experience to issue
+	 the "invalid argument" error before any missing
+	 argument error.  */
+      if (oarg == NULL && !dont_throw)
+	error (_("missing argument for \"%s\""), opt);
+
+      /* The option/argument pari was successfully processed;
+	 oarg belongs to the explicit location, and opt should
+	 be freed.  */
+      do_cleanups (inner);
+    }
+
+  /* One special error check:  If a source filename was given
+     without offset, function, or label, issue an error.  */
+  if (EL_EXPLICIT (location)->source_filename != NULL
+      && EL_EXPLICIT (location)->function_name == NULL
+      && EL_EXPLICIT (location)->label_name == NULL
+      && (EL_EXPLICIT (location)->line_offset.sign == LINE_OFFSET_UNKNOWN)
+      && !dont_throw)
+    {
+      error (_("Source filename requires function, label, or "
+	       "line offset."));
+    }
+
+  discard_cleanups (cleanup);
+  return location;
+}
+
 /* See description in location.h.  */
 
 struct event_location *
@@ -474,8 +671,22 @@ string_to_event_location (char **stringp,
 	}
       else
 	{
-	  /* Everything else is a linespec.  */
-	  location = new_linespec_location (stringp);
+	  const char *arg, *orig;
+
+	  /* Next, try an explicit location.  */
+	  orig = arg = *stringp;
+	  location = string_to_explicit_location (&arg, language, 0);
+	  if (location != NULL)
+	    {
+	      /* It was a valid explicit location.  Advance STRINGP to
+		 the end of input.  */
+	      *stringp += arg - orig;
+	    }
+	  else
+	    {
+	      /* Everything else is a linespec.  */
+	      location = new_linespec_location (stringp);
+	    }
 	}
     }
 
diff --git a/gdb/location.h b/gdb/location.h
index fba1c17..9dc557d 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -210,6 +210,21 @@ extern struct event_location *
   string_to_event_location (char **argp,
 			    const struct language_defn *langauge);
 
+/* Attempt to convert the input string in *ARGP into an explicit location.
+   ARGP is advanced past any processed input.  Returns an event_location
+   (malloc'd) if an explicit location was successfully found in *ARGP,
+   NULL otherwise.
+
+   IF !DONT_THROW, this function may call error() if *ARGP looks like
+   properly formed input, e.g., if it is called with missing argument
+   parameters or invalid options.  If DONT_THROW is non-zero, this function
+   will not throw any exceptions.  */
+
+extern struct event_location *
+  string_to_explicit_location (const char **argp,
+			       const struct language_defn *langauge,
+			       int dont_throw);
+
 /* A convenience function for testing for unset locations.  */
 
 extern int event_location_empty_p (const struct event_location *location);
diff --git a/gdb/testsuite/gdb.linespec/3explicit.c b/gdb/testsuite/gdb.linespec/3explicit.c
new file mode 100644
index 0000000..12bf277
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/3explicit.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static int
+myfunction4 (int arg)
+{
+  return arg + 2;
+}
+
+int
+myfunction3 (int arg)
+{
+  return myfunction4 (arg);
+}
diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.cc b/gdb/testsuite/gdb.linespec/cpexplicit.cc
new file mode 100644
index 0000000..42d50c7
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.cc
@@ -0,0 +1,63 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class myclass
+{
+public:
+  static int myfunction (int arg)  /* entry location */
+  {
+    int i, j, r;
+
+    j = 0; /* myfunction location */
+    r = arg;
+
+  top:
+    ++j;  /* top location */
+
+    if (j == 10)
+      goto done;
+
+    for (i = 0; i < 10; ++i)
+      {
+	r += i;
+	if (j % 2)
+	  goto top;
+      }
+
+  done:
+    return r;
+  }
+
+  int operator, (const myclass& c) { return 0; } /* operator location */
+};
+
+int
+main (void)
+{
+  int i, j;
+
+  /* Call the test function repeatedly, enough times for all our tests
+     without running forever if something goes wrong.  */
+  myclass c, d;
+  for (i = 0, j = 0; i < 1000; ++i)
+    {
+      j += myclass::myfunction (0);
+      j += (c,d);
+    }
+
+  return j;
+}
diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.exp b/gdb/testsuite/gdb.linespec/cpexplicit.exp
new file mode 100644
index 0000000..90c8ce8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
@@ -0,0 +1,112 @@
+# Copyright 2012-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit linespecs
+
+if {[skip_cplus_tests]} {
+    unsupported "skipping C++ tests"
+    return
+}
+
+standard_testfile .cc
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile $srcfile \
+	 {c++ debug nowarnings}]} {
+    return -1
+}
+
+# Wrap this whole test in a namespace to avoid contaminating other tests.
+namespace eval $testfile {
+    # Test the given (explicit) LINESPEC which should cause gdb to break
+    # at LOCATION.
+    proc test_breakpoint {linespec location} {
+
+	# Delete all breakpoints, set a new breakpoint at LINESPEC,
+	# and attempt to run to it.
+	delete_breakpoints
+	gdb_breakpoint $linespec
+	gdb_continue_to_breakpoint $linespec $location
+    }
+
+    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+    # to stop at LOCATION.
+    proc add {thearray linespec location} {
+	upvar $thearray ar
+
+	lappend ar(linespecs) $linespec
+	lappend ar(locations) $location
+    }
+
+    # Some locations used in this test
+    variable lineno
+    variable location
+    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+    set lineno(entry) [gdb_get_line_number "entry location" $srcfile]
+    set lineno(top) [gdb_get_line_number "top location" $srcfile]
+    set lineno(operator) [gdb_get_line_number "operator location" $srcfile]
+    foreach v [array names lineno] {
+	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+    }
+
+    # A list of explicit linespecs and the corresponding location
+    variable linespecs
+    set linespecs(linespecs) {}
+    set linespecs(location) {}
+
+    add linespecs "-source $srcfile -function myclass::myfunction" \
+	$location(normal)
+    add linespecs "-source $srcfile -function myclass::myfunction -label top" \
+	$location(top)
+
+    # This isn't implemented yet; -line is silently ignored.
+    add linespecs \
+	"-source $srcfile -function myclass::myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+    add linespecs "-function myclass::myfunction" $location(normal)
+    add linespecs "-function myclass::myfunction -label top" $location(top)
+
+    # These are also not yet supported; -line is silently ignored.
+    add linespecs "-function myclass::myfunction -line 3" $location(normal)
+    add linespecs "-function myclass::myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-line 3" $location(normal)
+    add linespecs "-function myclass::operator," $location(operator)
+    add linespecs "-function 'myclass::operator,'" $location(operator)
+    add linespecs "-function \"myclass::operator,\"" $location(operator)
+
+    # Fire up gdb.
+    if {![runto_main]} {
+	namespace delete $testfile
+	return -1
+    }
+
+    # Test explicit linespecs, with and without conditions.
+    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+	# Test the linespec
+	test_breakpoint $linespec $loc_pattern
+    }
+
+    # Special (orphaned) dprintf cases.
+    gdb_test "dprintf -function myclass::operator,,\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+    gdb_test "dprintf -function 'myclass::operator,',\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+    gdb_test "dprintf -function \"myclass::operator,\",\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+}
+
+namespace delete $testfile
diff --git a/gdb/testsuite/gdb.linespec/explicit.c b/gdb/testsuite/gdb.linespec/explicit.c
new file mode 100644
index 0000000..4e1c635
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.c
@@ -0,0 +1,56 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction2 (int arg);
+
+static int
+myfunction (int arg)
+{
+  int i, j, r;
+
+  j = 0; /* myfunction location */
+  r = arg;
+
+ top:
+  ++j;  /* top location */
+
+  if (j == 10)
+    goto done;
+
+  for (i = 0; i < 10; ++i)
+    {
+      r += i;
+      if (j % 2)
+	goto top;
+    }
+
+ done:
+  return r;
+}
+
+int
+main (void)
+{
+  int i, j;
+
+  /* Call the test function repeatedly, enough times for all our tests
+     without running forever if something goes wrong.  */
+  for (i = 0, j = 0; i < 1000; ++i)
+    j += myfunction (0);
+
+  return myfunction2 (j);
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
new file mode 100644
index 0000000..ce65bfd
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,393 @@
+# Copyright 2012-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit locations
+
+standard_testfile explicit.c explicit2.c 3explicit.c
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile \
+	 [list $srcfile $srcfile2 $srcfile3] {debug nowarnings}]} {
+    return -1
+}
+
+# Wrap the entire test in a namespace to avoid contaminating other tests.
+namespace eval $testfile {
+
+    # Test the given (explicit) LINESPEC which should cause gdb to break
+    # at LOCATION.
+    proc test_breakpoint {linespec location} {
+
+	set testname "set breakpoint at \"$linespec\""
+	# Delete all breakpoints, set a new breakpoint at LINESPEC,
+	# and attempt to run to it.
+	delete_breakpoints
+	if {[gdb_breakpoint $linespec]} {
+	    pass $testname
+	    send_log "\nexpecting locpattern \"$location\"\n"
+	    gdb_continue_to_breakpoint $linespec $location
+	} else {
+	    fail $testname
+	}
+    }
+
+    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+    # to stop at LOCATION.
+    proc add {thearray linespec location} {
+	upvar $thearray ar
+
+	lappend ar(linespecs) $linespec
+	lappend ar(locations) $location
+    }
+
+    # A list of all explicit linespec arguments.
+    variable all_arguments
+    set all_arguments {"source" "function" "label" "line"}
+
+    # Some locations used in this test
+    variable lineno
+    variable location
+    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+    set lineno(top) [gdb_get_line_number "top location" $srcfile]
+    foreach v [array names lineno] {
+	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+    }
+
+    # A list of explicit locations and the corresponding location.
+    variable linespecs
+    set linespecs(linespecs) {}
+    set linespecs(location) {}
+
+    add linespecs "-source $srcfile -function myfunction" $location(normal)
+    add linespecs "-source $srcfile -function myfunction -label top" \
+	$location(top)
+
+    # This isn't implemented yet; -line is silently ignored.
+    add linespecs "-source $srcfile -function myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+    add linespecs "-function myfunction" $location(normal)
+    add linespecs "-function myfunction -label top" $location(top)
+
+    # These are also not yet supported; -line is silently ignored.
+    add linespecs "-function myfunction -line 3" $location(normal)
+    add linespecs "-function myfunction -label top -line 3" $location(top)
+    add linespecs "-line 3" $location(normal)
+
+    # Test that static tracepoints on marker ID are not interpreted
+    # as an erroneous explicit option.
+    gdb_test "strace -m gdbfoobarbaz" "You can't do that.*"
+
+    # Fire up gdb.
+    if {![runto_main]} {
+	return -1
+    }
+
+    # Turn off queries
+    gdb_test_no_output "set confirm off"
+
+    # Simple error tests (many more are tested in ls-err.exp)
+    foreach arg $all_arguments {
+	# Test missing argument
+	gdb_test "break -$arg" \
+	    [string_to_regexp "missing argument for \"-$arg\""]
+
+	# Test abbreviations
+	set short [string range $arg 0 3]
+	gdb_test "break -$short" \
+	    [string_to_regexp "missing argument for \"-$short\""]
+    }
+
+    # Test invalid arguments
+    foreach arg {"-foo" "-foo bar" "-function myfunction -foo" \
+		     "-function -myfunction -foo bar"} {
+	gdb_test "break $arg" \
+	    [string_to_regexp "invalid explicit location argument, \"-foo\""]
+    }
+
+    # Test explicit locations, with and without conditions.
+    # For these tests, it is easiest to turn of pending breakpoint.
+    gdb_test_no_output "set breakpoint pending off" \
+	"turn off pending breakpoints"
+
+    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+
+	# Test the linespec
+	test_breakpoint $linespec $loc_pattern
+
+	# Test with a valid condition
+	delete_breakpoints
+	set tst "set breakpoint at \"$linespec\" with valid condition"
+	if {[gdb_breakpoint "$linespec if arg == 0"]} {
+	    pass $tst
+
+	    gdb_test "info break" ".*stop only if arg == 0.*" \
+		"info break of conditional breakpoint at \"$linespec\""
+	} else {
+	    fail $tst
+	}
+
+	# Test with invalid condition
+	gdb_test "break $linespec if foofoofoo == 1" \
+	    ".*No symbol \"foofoofoo\" in current context.*" \
+	    "set breakpoint at \"$linespec\" with invalid condition"
+
+	# Test with thread
+	delete_breakpoints
+	gdb_test "break $linespec thread 123" "Unknown thread 123."
+    }
+
+    # Test the explicit location completer
+    foreach abbrev {"fun" "so" "lab" "li"}  full {"function" "source" "label" "line"} {
+	set tst "complete 'break -$abbrev'"
+	send_gdb "break -${abbrev}\t"
+	gdb_test_multiple "" $tst {
+	    "break -$full " {
+		send_gdb "\n"
+		gdb_test_multiple "" $tst {
+		    -re "missing argument for \"-$full\".*$gdb_prompt " {
+			pass $tst
+		    }
+		}
+	    }
+	}
+	set tst "complete -$full with no value"
+	send_gdb "break -$full \t"
+	gdb_test_multiple "" $tst {
+	    -re ".*break -$full " {
+		send_gdb "\n"
+		gdb_test_multiple "" $tst {
+		    -re ".*Source filename requires function, label, or line offset\..*$gdb_prompt " {
+			if {[string equal $full "source"]} {
+			    pass $tst
+			} else {
+			    faill $tst
+			}
+		    }
+		    -re "missing argument for \"-$full\".*$gdb_prompt " {
+			pass $tst
+		    }
+		}
+	    }
+	}
+    }
+
+    set tst "complete unique function name"
+    send_gdb "break -function mai\t"
+    gdb_test_multiple "" $tst {
+	"break -function mai\\\x07n" {
+	    send_gdb "\n"
+	    gdb_test "" ".*Breakpoint \[0-9\]+.*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+
+    set tst "complete non-unique function name"
+    send_gdb "break -function myfunc\t"
+    gdb_test_multiple "" $tst {
+	"break -function myfunc\\\x07tion" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nmyfunction\[ \t\]+myfunction2\[ \t\]+myfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
+		    gdb_test "2" ".*Breakpoint \[0-9\]+.*" $tst
+		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+		}
+	    }
+	}
+    }
+
+    set tst "complete non-existant function name"
+    send_gdb "break -function foo\t"
+    gdb_test_multiple "" $tst {
+	"break -function foo\\\x07" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" {Function "foo" not defined.} $tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete unique file name"
+    send_gdb "break -source 3ex\t"
+    gdb_test_multiple "" $tst {
+	"break -source 3explicit.c " {
+	    send_gdb "\n"
+	    gdb_test "" \
+		{Source filename requires function, label, or line offset.} $tst
+	}
+    }
+
+    set tst "complete non-unique file name"
+    send_gdb "break -source exp\t"
+    gdb_test_multiple "" $tst {
+	"break -source exp\\\x07licit" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+\r\n$gdb_prompt" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+
+	"break -source exp\\\x07l" {
+	    # This pattern may occur when glibc debuginfo is installed.
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+expl.*\r\n$gdb_prompt" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete non-existant file name"
+    send_gdb "break -source foo\t"
+    gdb_test_multiple "" $tst {
+	"break -source foo" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		"\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete filename and unique function name"
+    send_gdb "break -source explicit.c -function ma\t"
+    gdb_test_multiple "" $tst {
+	"break -source explicit.c -function main " {
+	    send_gdb "\n"
+	    gdb_test "" ".*Breakpoint .*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+
+    set tst "complete filename and non-unique function name"
+    send_gdb "break -so 3explicit.c -func myfunc\t"
+    gdb_test_multiple "" $tst {
+	"break -so 3explicit.c -func myfunc\\\x07tion" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nmyfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
+		    gdb_test "3" ".*Breakpoint \[0-9\]+.*" $tst
+		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+		}
+	    }
+	}
+    }
+
+    set tst "complete filename and non-existant function name"
+    send_gdb "break -sou 3explicit.c -fun foo\t"
+    gdb_test_multiple "" $tst {
+	"break -sou 3explicit.c -fun foo\\\x07" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		"\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Function "foo" not defined in "3explicit.c".} $tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete filename and function reversed"
+    send_gdb "break -func myfunction4 -source 3ex\t"
+    gdb_test_multiple "" $tst {
+	"break -func myfunction4 -source 3explicit.c " {
+	    send_gdb "\n"
+	    gdb_test "" "Breakpoint \[0-9\]+.*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+
+    # NOTE: We don't bother testing more elaborate combinations of options,
+    # such as "-func main -sour 3ex\t" (main is defined in explicit.c).  The
+    # completer cannot handle these yet.
+
+    # Test pending explicit breakpoints
+    gdb_exit
+    gdb_start
+
+    set tst "pending invalid conditional explicit breakpoint"
+    if {![gdb_breakpoint "-func myfunction if foofoofoo == 1" \
+	      allow-pending]} {
+	fail "set $tst"
+    } else {
+	gdb_test "info break" ".*PENDING.*myfunction if foofoofoo == 1.*" $tst
+    }
+
+    gdb_exit
+    gdb_start
+
+    set tst "pending valid conditional explicit breakpoint"
+    if {![gdb_breakpoint "-func myfunction if arg == 0" \
+	      allow-pending]} {
+	fail "set $tst"
+    } else {
+	gdb_test "info break" ".*PENDING.*myfunction if arg == 0" $tst
+
+	gdb_load [standard_output_file $exefile]
+	gdb_test "info break" \
+	    ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" \
+	    "$tst resolved"
+    }
+
+    # Test interaction of condition command and explicit linespec conditons.
+    gdb_exit
+    gdb_start
+    gdb_load [standard_output_file $exefile]
+
+    set tst "condition_command overrides explicit linespec condition"
+    if {![runto main]} {
+	fail $tst
+    } else {
+	if {![gdb_breakpoint "-func myfunction if arg == 1"]} {
+	    fail "set breakpoint with condition 'arg == 1'"
+	} else {
+	    gdb_test_no_output "cond 2 arg == 0" \
+		"set new breakpoint condition for explicit linespec"
+
+	    gdb_continue_to_breakpoint $tst $location(normal)
+	}
+    }
+
+    gdb_test "cond 2" [string_to_regexp "Breakpoint 2 now unconditional."] \
+	"clear condition for explicit breakpoint"
+    set tst "info break of cleared condition of explicit breakpoint"
+    gdb_test_multiple "info break" $tst {
+	-re ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" {
+	    fail $tst
+	}
+	-re ".*in myfunction at .*$srcfile:.*$gdb_prompt $" {
+	    pass $tst
+	}
+    }
+}
+
+namespace delete $testfile
diff --git a/gdb/testsuite/gdb.linespec/explicit2.c b/gdb/testsuite/gdb.linespec/explicit2.c
new file mode 100644
index 0000000..218cccb
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit2.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction3 (int arg);
+
+int
+myfunction2 (int arg)
+{
+  return myfunction3 (arg);
+}
diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp
index 019312c..c220241 100644
--- a/gdb/testsuite/gdb.linespec/ls-errs.exp
+++ b/gdb/testsuite/gdb.linespec/ls-errs.exp
@@ -49,11 +49,16 @@ array set error_messages {
     invalid_var_or_func_f \
 	"Undefined convenience variable or function \"%s\" not defined in \"%s\"."
     invalid_label "No label \"%s\" defined in function \"%s\"."
+    invalid_parm "invalid linespec argument, \"%s\""
     invalid_offset "No line %d in the current file."
     invalid_offset_f "No line %d in file \"%s\"."
+    malformed_line_offset "malformed line offset: \"%s\""
+    source_incomplete \
+	"Source filename requires function, label, or line offset."
     unexpected "malformed linespec error: unexpected %s"
     unexpected_opt "malformed linespec error: unexpected %s, \"%s\""
     unmatched_quote "unmatched quote"
+    garbage "Garbage '%s' at end of command"
 }
 
 # Some commonly used whitespace tests around ':'.
@@ -80,6 +85,7 @@ foreach x $invalid_offsets {
 	incr offset 16
     }
     test_break $x invalid_offset $offset
+    test_break "-line $x" invalid_offset $offset
 }
 
 # Test offsets with trailing tokens w/ and w/o spaces.
@@ -91,13 +97,17 @@ foreach x $spaces {
 
 foreach x {1 +1 +100 -10} {
     test_break "3 $x" unexpected_opt "number" $x
+    test_break "-line 3 $x" garbage $x
     test_break "+10 $x" unexpected_opt "number" $x
+    test_break "-line +10 $x" garbage $x
     test_break "-10 $x" unexpected_opt "number" $x
+    test_break "-line -10 $x" garbage $x
 }
 
-test_break "3 foo" unexpected_opt "string" "foo"
-test_break "+10 foo" unexpected_opt "string" "foo"
-test_break "-10 foo" unexpected_opt "string" "foo"
+foreach x {3 +10 -10} {
+    test_break "$x foo" unexpected_opt "string" "foo"
+    test_break "-line $x foo" garbage "foo"
+}
 
 # Test invalid linespecs starting with filename.
 foreach x [list "this_file_doesn't_exist.c" \
@@ -113,6 +123,13 @@ foreach x [list "this_file_doesn't_exist.c" \
     # Remove any quoting from FILENAME for the error message.
     test_break "$x:3" invalid_file [string trim $x \"']
 }
+foreach x [list "this_file_doesn't_exist.c" \
+	       "this file has spaces.c" \
+	       "file::colons.c" \
+	       "'file::colons.c'"] {
+    test_break "-source $x -line 3" \
+	invalid_file [string trim $x \"']
+}
 
 # Test unmatched quotes.
 foreach x {"\"src-file.c'" "'src-file.c"} {
@@ -123,7 +140,11 @@ test_break $srcfile invalid_function $srcfile
 foreach x {"foo" " foo" " foo "} {
     # Trim any leading/trailing whitespace for error messages.
     test_break "$srcfile:$x" invalid_function_f [string trim $x] $srcfile
+    test_break "-source $srcfile -function $x" \
+	invalid_function_f [string trim $x] $srcfile
     test_break "$srcfile:main:$x" invalid_label [string trim $x] "main"
+    test_break "-source $srcfile -function main -label $x" \
+	invalid_label [string trim $x] "main"
 }
 
 foreach x $spaces {
@@ -133,20 +154,26 @@ foreach x $spaces {
 
 test_break "${srcfile}::" invalid_function "${srcfile}::"
 test_break "$srcfile:3 1" unexpected_opt "number" "1"
+test_break "-source $srcfile -line 3 1" garbage "1"
 test_break "$srcfile:3 +100" unexpected_opt "number" "+100"
+test_break "-source $srcfile -line 3 +100" garbage "+100"
 test_break "$srcfile:3 -100" unexpected_opt "number" "-100"
 test_break "$srcfile:3 foo" unexpected_opt "string" "foo"
+test_break "-source $srcfile -line 3 foo" garbage "foo"
 
 foreach x $invalid_offsets {
     test_break "$srcfile:$x" invalid_offset_f $x $srcfile
     test_break "\"$srcfile:$x\"" invalid_offset_f $x $srcfile
     test_break "'$srcfile:$x'" invalid_offset_f $x $srcfile
+    test_break "-source $srcfile -line $x" invalid_offset_f $x $srcfile
 }
+test_break "-source $srcfile -line -x" malformed_line_offset "-x"
 
 # Test invalid filespecs starting with function.
 foreach x {"foobar" "foo::bar" "foo.bar" "foo ." "foo bar" "foo 1" \
 	       "foo 0" "foo +10" "foo -10" "foo +100" "foo -100"} {
     test_break $x invalid_function $x
+    test_break "-function \"$x\"" invalid_function $x
 }
 
 foreach x $spaces {
@@ -155,13 +182,12 @@ foreach x $spaces {
     test_break "main:here${x}" unexpected "end of input"
 }
 
-test_break "main 3" invalid_function "main 3"
-test_break "main +100" invalid_function "main +100"
-test_break "main -100" invalid_function "main -100"
-test_break "main foo" invalid_function "main foo"
-
 foreach x {"3" "+100" "-100" "foo"} {
+    test_break "main 3" invalid_function "main 3"
+    test_break "-function \"main $x\"" invalid_function "main $x"
     test_break "main:here $x" invalid_label "here $x" "main"
+    test_break "-function main -label \"here $x\"" \
+	invalid_label "here $x" "main"
 }
 
 foreach x {"if" "task" "thread"} {
@@ -178,3 +204,6 @@ test_break "'main.c'+3" unexpected_opt "number" "+3"
 set x {$zippo}
 test_break $x invalid_var_or_func $x
 test_break "$srcfile:$x" invalid_var_or_func_f $x $srcfile
+
+# Explicit linespec-specific tests
+test_break "-source $srcfile" source_incomplete

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 5/9] Explicit locations: introduce probe locations
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (3 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 7/9] Explicit locations: add UI features for CLI Keith Seitz
@ 2015-05-07 18:06 ` Keith Seitz
  2015-05-18  5:49   ` Doug Evans
  2015-05-07 18:06 ` [PATCH v4 4/9] Explicit locations: introduce address locations Keith Seitz
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:06 UTC (permalink / raw)
  To: gdb-patches

This patch adds support for probe locations and converts existing
probe linespec locations to the new location type.

gdb/ChangeLog:

	* break-catch-throw.c (re_set_exception_catchpoint): Convert
	linespec for stap probe to probe location.
	* breakpoint.c (create_longjmp_master_breakpoint): Likewise.
	(create_exception_master_breakpoint): Likewise.
	(break_command_1): Remove local variable `arg_cp'.
	Check location type to set appropriate breakpoint ops methods.
	(trace_command): Likewise.
	* linespec.c (event_location_to_sals): Assert on probe locations.
	* location.c (EL_PROBE): Add macro definition.
	(new_probe_location, get_probe_location): New functions.
	(copy_event_location): Handle probe locations.
	(delete_event_location): Likewise.
	(event_location_to_string): Likewise.
	(string_to_event_location): Likewise.
	(event_location_empty_p): Likewise.
	* location.h (enum event_location_type): Add PROBE_LOCATION.
	(new_probe_location, get_probe_location): Declare.
	* probe.c (parse_probes): Assert that LOCATION is a probe location.
	Convert linespec into probe location.
---
 gdb/break-catch-throw.c |    5 ++--
 gdb/breakpoint.c        |   18 +++++++--------
 gdb/linespec.c          |    5 ++++
 gdb/location.c          |   56 +++++++++++++++++++++++++++++++++++++++++++++--
 gdb/location.h          |   17 +++++++++++++-
 gdb/probe.c             |    5 +++-
 6 files changed, 88 insertions(+), 18 deletions(-)

diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 9449aa5..07a8f05 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -216,9 +216,8 @@ re_set_exception_catchpoint (struct breakpoint *self)
   /* We first try to use the probe interface.  */
   TRY
     {
-      char *spec = ASTRDUP (exception_functions[kind].probe);
-
-      location = new_linespec_location (&spec);
+      location
+	= new_probe_location (exception_functions[kind].probe);
       cleanup = make_cleanup_delete_event_location (location);
       sals = parse_probes (location, NULL);
       do_cleanups (cleanup);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c1d8ddc..9f879ed 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3507,7 +3507,6 @@ create_longjmp_master_breakpoint (void)
 	  int i;
 	  struct probe *probe;
 	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
-	  char *p;
 
 	  for (i = 0;
 	       VEC_iterate (probe_p,
@@ -3522,8 +3521,8 @@ create_longjmp_master_breakpoint (void)
 								 objfile),
 					      bp_longjmp_master,
 					      &internal_breakpoint_ops);
-	      p = ASTRDUP ("-probe-stap libc:longjmp");
-	      b->location = new_linespec_location (&p);
+	      b->location
+		= new_probe_location ("-probe-stap libc:longjmp");
 	      b->enable_state = bp_disabled;
 	    }
 
@@ -3685,15 +3684,14 @@ create_exception_master_breakpoint (void)
 	       ++i)
 	    {
 	      struct breakpoint *b;
-	      char *p;
 
 	      b = create_internal_breakpoint (gdbarch,
 					      get_probe_address (probe,
 								 objfile),
 					      bp_exception_master,
 					      &internal_breakpoint_ops);
-	      p = ASTRDUP ("-probe-stap libgcc:unwind");
-	      b->location = new_linespec_location (&p);
+	      b->location
+		= new_probe_location ("-probe-stap libgcc:unwind");
 	      b->enable_state = bp_disabled;
 	    }
 
@@ -9867,7 +9865,6 @@ break_command_1 (char *arg, int flag, int from_tty)
 			     ? bp_hardware_breakpoint
 			     : bp_breakpoint);
   struct breakpoint_ops *ops;
-  const char *arg_cp = arg;
   struct event_location *location;
   struct cleanup *cleanup;
 
@@ -9875,7 +9872,8 @@ break_command_1 (char *arg, int flag, int from_tty)
   cleanup = make_cleanup_delete_event_location (location);
 
   /* Matching breakpoints on probes.  */
-  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
+  if (location != NULL
+      && event_location_type (location) == PROBE_LOCATION)
     ops = &bkpt_probe_breakpoint_ops;
   else
     ops = &bkpt_breakpoint_ops;
@@ -14991,11 +14989,11 @@ trace_command (char *arg, int from_tty)
   struct breakpoint_ops *ops;
   struct event_location *location;
   struct cleanup *back_to;
-  const char *arg_cp = arg;
 
   location = string_to_event_location (&arg, current_language);
   back_to = make_cleanup_delete_event_location (location);
-  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
+  if (location != NULL
+      && event_location_type (location) == PROBE_LOCATION)
     ops = &tracepoint_probe_breakpoint_ops;
   else
     ops = &tracepoint_breakpoint_ops;
diff --git a/gdb/linespec.c b/gdb/linespec.c
index c4cbe13..fa7e3f4 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -2486,6 +2486,11 @@ event_location_to_sals (linespec_parser *parser,
 					    get_address_location (location));
       break;
 
+    case PROBE_LOCATION:
+      /* Probes are handled by their own decoders.  */
+      gdb_assert_not_reached ("attempt to decode probe location");
+      break;
+
     default:
       gdb_assert_not_reached ("unhandled event location type");
     }
diff --git a/gdb/location.c b/gdb/location.c
index c1f4e19..6059679 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -45,6 +45,7 @@ struct event_location
        probes.  */
     char *addr_string;
 #define EL_LINESPEC(PTR) ((PTR)->u.addr_string)
+#define EL_PROBE(PTR) ((PTR)->u.addr_string)
 
     /* An address in the inferior.  */
     CORE_ADDR address;
@@ -121,6 +122,29 @@ get_address_location (const struct event_location *location)
 /* See description in location.h.  */
 
 struct event_location *
+new_probe_location (const char *probe)
+{
+  struct event_location *location;
+
+  location = XCNEW (struct event_location);
+  EL_TYPE (location) = PROBE_LOCATION;
+  if (probe != NULL)
+    EL_PROBE (location) = xstrdup (probe);
+  return location;
+}
+
+/* See description in location.h.  */
+
+const char *
+get_probe_location (const struct event_location *location)
+{
+  gdb_assert (EL_TYPE (location) == PROBE_LOCATION);
+  return EL_PROBE (location);
+}
+
+/* See description in location.h.  */
+
+struct event_location *
 copy_event_location (const struct event_location *src)
 {
   struct event_location *dst;
@@ -141,6 +165,11 @@ copy_event_location (const struct event_location *src)
       EL_ADDRESS (dst) = EL_ADDRESS (src);
       break;
 
+    case PROBE_LOCATION:
+      if (EL_PROBE (src) != NULL)
+	EL_PROBE (dst) = xstrdup (EL_PROBE (src));
+      break;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
@@ -185,6 +214,10 @@ delete_event_location (struct event_location *location)
 	  /* Nothing to do.  */
 	  break;
 
+	case PROBE_LOCATION:
+	  xfree (EL_PROBE (location));
+	  break;
+
 	default:
 	  gdb_assert_not_reached ("unknown event location type");
 	}
@@ -216,6 +249,10 @@ event_location_to_string_const (const struct event_location *location)
 		      core_addr_to_string (EL_ADDRESS (location)));
       break;
 
+    case PROBE_LOCATION:
+      result = xstrdup (EL_PROBE (location));
+      break;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
@@ -256,8 +293,20 @@ string_to_event_location (char **stringp,
     }
   else
     {
-      /* Everything else is a linespec.  */
-      location = new_linespec_location (stringp);
+      const char *cs;
+
+      /* Next, try the input as a probe spec.  */
+      cs = *stringp;
+      if (cs != NULL && probe_linespec_to_ops (&cs) != NULL)
+	{
+	  location = new_probe_location (*stringp);
+	  *stringp += strlen (*stringp);
+	}
+      else
+	{
+	  /* Everything else is a linespec.  */
+	  location = new_linespec_location (stringp);
+	}
     }
 
   return location;
@@ -277,6 +326,9 @@ event_location_empty_p (const struct event_location *location)
     case ADDRESS_LOCATION:
       return 0;
 
+    case PROBE_LOCATION:
+      return EL_PROBE (location) == NULL;
+
     default:
       gdb_assert_not_reached ("unknown event location type");
     }
diff --git a/gdb/location.h b/gdb/location.h
index 39db10e..3112d63 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -31,7 +31,10 @@ enum event_location_type
   LINESPEC_LOCATION,
 
   /* An address in the inferior.  */
-  ADDRESS_LOCATION
+  ADDRESS_LOCATION,
+
+  /* A probe location.  */
+  PROBE_LOCATION
 };
 
 /* Return the type of the given event location.  */
@@ -79,6 +82,18 @@ extern struct event_location *
 extern CORE_ADDR
   get_address_location (const struct event_location *location);
 
+/* Create a new probe location.  The return result is malloc'd
+   and should be freed with delete_event_location.  */
+
+extern struct event_location *
+  new_probe_location (const char *probe);
+
+/* Return the probe location (a string) of the given event_location
+   (which must be of type PROBE_LOCATION).  */
+
+extern const char *
+  get_probe_location (const struct event_location *location);
+
 /* Free an event location and any associated data.  */
 
 extern void delete_event_location (struct event_location *location);
diff --git a/gdb/probe.c b/gdb/probe.c
index 8366220..a3cfefe 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -59,7 +59,8 @@ parse_probes (const struct event_location *location,
   result.sals = NULL;
   result.nelts = 0;
 
-  arg_start = get_linespec_location (location);
+  gdb_assert (event_location_type (location) == PROBE_LOCATION);
+  arg_start = get_probe_location (location);
 
   cs = arg_start;
   probe_ops = probe_linespec_to_ops (&cs);
@@ -178,7 +179,7 @@ parse_probes (const struct event_location *location,
       make_cleanup (xfree, canon);
       canonical->special_display = 1;
       canonical->pre_expanded = 1;
-      canonical->location = new_linespec_location (&canon);
+      canonical->location = new_probe_location (canon);
     }
 
   do_cleanups (cleanup);

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v4 9/9] Explicit locations: documentation updates
  2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
                   ` (7 preceding siblings ...)
  2015-05-07 18:06 ` [PATCH v4 3/9] Explicit locations: use new location API Keith Seitz
@ 2015-05-07 18:13 ` Keith Seitz
  2015-05-07 18:55   ` Eli Zaretskii
  8 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-07 18:13 UTC (permalink / raw)
  To: gdb-patches

This patch adds documentation for explicit locations to both the
User Manual and gdb's online help system.

gdb/ChangeLog:

	* NEWS: Mention explicit locations.
	* breakpoint.c [LOCATION_HELP_STRING]: New macro.
	[BREAK_ARGS_HELP]: Use LOCATION_HELP_STRING.
	(_initialize_breakpoint): Update documentation for
	"clear", "break", "trace", "strace", "ftrace", and "dprintf".

gdb/doc/ChangeLog:

	* gdb.texinfo (Thread-Specific Breakpoints): Use "location(s)"
	instead of "linespec(s)".
	(Printing Source Lines): Likewise.
	(Specifying a Location): Rewrite.  Add explanations for each
	location type.
	(Source and Machine Code): Use "location(s)" instead of
	"linespec(s)".
	(C Preprocessor Macros): Likewise.
	(Create and Delete Tracepoints): Likewise.
	(Extensions for Ada Tasks): Likewise.
	(Continuing at a Different Address): Remove "linespec" examples.
	Add reference to "Specify a Location"
	(The -break-insert Command): Rewrite.  Add anchor.
	Add reference to appropriate manual section discussing locations.
	(The -dprintf-insert Command): Refer to -break-insert for
	specification of 'location'.

gdb/testsuite/ChangeLog:

	* gdb.base/help.exp: Update help_breakpoint_text.
---
 gdb/NEWS                        |    4 +
 gdb/breakpoint.c                |   70 +++++++-----
 gdb/doc/gdb.texinfo             |  234 +++++++++++++++++++++++++--------------
 gdb/testsuite/gdb.base/help.exp |    2 
 4 files changed, 195 insertions(+), 115 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 0c7084a..9eaa69b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -270,6 +270,10 @@ VAX running Ultrix 			vax-*-ultrix*
 -D data-directory
   This is an alias for the --data-directory option.
 
+* GDB now allows users to specify explicit locations, bypassing
+  the linespec parser.  This feature is also available to GDB/MI
+  clients.
+
 * GDB supports printing and modifying of variable length automatic arrays
   as specified in ISO C99.
 
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 58c3cd7..e4bcab4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -15574,26 +15574,46 @@ all_tracepoints (void)
 }
 
 \f
+/* This help string is used to consolidate all the help string for specifying
+   locations used by several commands.  */
+
+#define LOCATION_HELP_STRING \
+"Linespecs are colon-separated lists of location parameters, such as\n\
+source filename, function name, label name, and line number.\n\
+Example: To specify the start of a label named \"the_top\" in the\n\
+function \"fact\" in the file \"factorial.c\", use\n\
+\"factorial.c:fact:the_top\".\n\
+\n\
+Address locations begin with \"*\" and specify an exact address in the\n\
+program.  Example: To specify the fourth byte past the start function\n\
+\"main\", use \"*main + 4\".\n\
+\n\
+Explicit locations are similar to linespecs but use an option/argument\n\
+syntax to specify location parameters.\n\
+Example: To specify the start of the label named \"the_top\" in the\n\
+function \"fact\" in the file \"factorial.c\", use \"-source factorial.c\n\
+-function fact -label the_top\".\n"
+
 /* This help string is used for the break, hbreak, tbreak and thbreak
    commands.  It is defined as a macro to prevent duplication.
    COMMAND should be a string constant containing the name of the
    command.  */
+
 #define BREAK_ARGS_HELP(command) \
 command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
 PROBE_MODIFIER shall be present if the command is to be placed in a\n\
 probe point.  Accepted values are `-probe' (for a generic, automatically\n\
 guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
 `-probe-dtrace' (for a DTrace probe).\n\
-LOCATION may be a line number, function name, or \"*\" and an address.\n\
-If a line number is specified, break at start of code for that line.\n\
-If a function is specified, break at start of code for that function.\n\
-If an address is specified, break at that exact address.\n\
+LOCATION may be a linespec, address, or explicit location as described\n\
+below.\n\
+\n\
 With no LOCATION, uses current execution address of the selected\n\
 stack frame.  This is useful for breaking on return to a stack frame.\n\
 \n\
 THREADNUM is the number from \"info threads\".\n\
 CONDITION is a boolean expression.\n\
-\n\
+\n" LOCATION_HELP_STRING "\n\
 Multiple breakpoints at one place are permitted, and useful if their\n\
 conditions are different.\n\
 \n\
@@ -16040,20 +16060,17 @@ This command may be abbreviated \"delete\"."),
 	   &deletelist);
 
   add_com ("clear", class_breakpoint, clear_command, _("\
-Clear breakpoint at specified line or function.\n\
-Argument may be line number, function name, or \"*\" and an address.\n\
-If line number is specified, all breakpoints in that line are cleared.\n\
-If function is specified, breakpoints at beginning of function are cleared.\n\
-If an address is specified, breakpoints at that address are cleared.\n\
+Clear breakpoint at specified location.\n\
+Argument may be a linespec, explicit, or address location as described below.\n\
 \n\
 With no argument, clears all breakpoints in the line that the selected frame\n\
-is executing in.\n\
-\n\
+is executing in.\n"
+"\n" LOCATION_HELP_STRING "\n\
 See also the \"delete\" command which clears breakpoints by number."));
   add_com_alias ("cl", "clear", class_breakpoint, 1);
 
   c = add_com ("break", class_breakpoint, break_command, _("\
-Set breakpoint at specified line or function.\n"
+Set breakpoint at specified location.\n"
 BREAK_ARGS_HELP ("break")));
   set_cmd_completer (c, location_completer);
 
@@ -16216,7 +16233,7 @@ hardware.)"),
   /* Tracepoint manipulation commands.  */
 
   c = add_com ("trace", class_breakpoint, trace_command, _("\
-Set a tracepoint at specified line or function.\n\
+Set a tracepoint at specified location.\n\
 \n"
 BREAK_ARGS_HELP ("trace") "\n\
 Do \"help tracepoints\" for info on other tracepoint commands."));
@@ -16228,31 +16245,27 @@ Do \"help tracepoints\" for info on other tracepoint commands."));
   add_com_alias ("trac", "trace", class_alias, 1);
 
   c = add_com ("ftrace", class_breakpoint, ftrace_command, _("\
-Set a fast tracepoint at specified line or function.\n\
+Set a fast tracepoint at specified location.\n\
 \n"
 BREAK_ARGS_HELP ("ftrace") "\n\
 Do \"help tracepoints\" for info on other tracepoint commands."));
   set_cmd_completer (c, location_completer);
 
   c = add_com ("strace", class_breakpoint, strace_command, _("\
-Set a static tracepoint at specified line, function or marker.\n\
+Set a static tracepoint at location or marker.\n\
 \n\
 strace [LOCATION] [if CONDITION]\n\
-LOCATION may be a line number, function name, \"*\" and an address,\n\
-or -m MARKER_ID.\n\
-If a line number is specified, probe the marker at start of code\n\
-for that line.  If a function is specified, probe the marker at start\n\
-of code for that function.  If an address is specified, probe the marker\n\
-at that exact address.  If a marker id is specified, probe the marker\n\
-with that name.  With no LOCATION, uses current execution address of\n\
-the selected stack frame.\n\
+LOCATION may be a linespec, explicit, or address location (described below) \n\
+or -m MARKER_ID.\n\n\
+If a marker id is specified, probe the marker with that name.  With\n\
+no LOCATION, uses current execution address of the selected stack frame.\n\
 Static tracepoints accept an extra collect action -- ``collect $_sdata''.\n\
 This collects arbitrary user data passed in the probe point call to the\n\
 tracing library.  You can inspect it when analyzing the trace buffer,\n\
 by printing the $_sdata variable like any other convenience variable.\n\
 \n\
 CONDITION is a boolean expression.\n\
-\n\
+\n" LOCATION_HELP_STRING "\n\
 Multiple tracepoints at one place are permitted, and useful if their\n\
 conditions are different.\n\
 \n\
@@ -16404,11 +16417,10 @@ an instruction at any address within the [START-LOCATION, END-LOCATION]\n\
 range (including START-LOCATION and END-LOCATION)."));
 
   c = add_com ("dprintf", class_breakpoint, dprintf_command, _("\
-Set a dynamic printf at specified line or function.\n\
+Set a dynamic printf at specified location.\n\
 dprintf location,format string,arg1,arg2,...\n\
-location may be a line number, function name, or \"*\" and an address.\n\
-If a line number is specified, break at start of code for that line.\n\
-If a function is specified, break at start of code for that function."));
+location may be a linespec, explicit, or address location.\n"
+"\n" LOCATION_HELP_STRING));
   set_cmd_completer (c, location_completer);
 
   add_setshow_enum_cmd ("dprintf-style", class_support,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 19d8bb3..6f7e16a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6057,9 +6057,9 @@ breakpoints on all threads, or on a particular thread.
 @cindex breakpoints and threads
 @cindex thread breakpoints
 @kindex break @dots{} thread @var{threadno}
-@item break @var{linespec} thread @var{threadno}
-@itemx break @var{linespec} thread @var{threadno} if @dots{}
-@var{linespec} specifies source lines; there are several ways of
+@item break @var{location} thread @var{threadno}
+@itemx break @var{location} thread @var{threadno} if @dots{}
+@var{location} specifies source lines; there are several ways of
 writing them (@pxref{Specify Location}), but the effect is always to
 specify some source line.
 
@@ -7485,21 +7485,21 @@ argument of @samp{-}; that argument is preserved in repetition so that
 each repetition moves up in the source file.
 
 In general, the @code{list} command expects you to supply zero, one or two
-@dfn{linespecs}.  Linespecs specify source lines; there are several ways
+@dfn{locations}.  Locations specify source lines; there are several ways
 of writing them (@pxref{Specify Location}), but the effect is always
 to specify some source line.
 
 Here is a complete description of the possible arguments for @code{list}:
 
 @table @code
-@item list @var{linespec}
-Print lines centered around the line specified by @var{linespec}.
+@item list @var{location}
+Print lines centered around the line specified by @var{location}.
 
 @item list @var{first},@var{last}
 Print lines from @var{first} to @var{last}.  Both arguments are
-linespecs.  When a @code{list} command has two linespecs, and the
-source file of the second linespec is omitted, this refers to
-the same source file as the first linespec.
+locations.  When a @code{list} command has two locations, and the
+source file of the second location is omitted, this refers to
+the same source file as the first location.
 
 @item list ,@var{last}
 Print lines ending with @var{last}.
@@ -7524,11 +7524,16 @@ As described in the preceding table.
 
 Several @value{GDBN} commands accept arguments that specify a location
 of your program's code.  Since @value{GDBN} is a source-level
-debugger, a location usually specifies some line in the source code;
-for that reason, locations are also known as @dfn{linespecs}.
+debugger, a location usually specifies some line in the source code.
+Locations may be specified using three different formats:
+linespec locations, explicit locations, or address locations.
 
-Here are all the different ways of specifying a code location that
-@value{GDBN} understands:
+@subsection Linespec Locations
+@anchor{Linespec Locations}
+
+A @dfn{linespec} is a colon-separated list of source location parameters such
+as file name, function name, etc.  Here are all the different ways of
+specifying a linespec:
 
 @table @code
 @item @var{linenum}
@@ -7567,25 +7572,93 @@ function name to avoid ambiguity when there are identically named
 functions in different source files.
 
 @item @var{label}
-Specifies the line at which the label named @var{label} appears.
-@value{GDBN} searches for the label in the function corresponding to
-the currently selected stack frame.  If there is no current selected
-stack frame (for instance, if the inferior is not running), then
-@value{GDBN} will not search for a label.
-
-@item *@var{address}
-Specifies the program address @var{address}.  For line-oriented
-commands, such as @code{list} and @code{edit}, this specifies a source
-line that contains @var{address}.  For @code{break} and other
-breakpoint oriented commands, this can be used to set breakpoints in
+Specifies the line at which the label named @var{label} appears
+in the function corresponding to the currently selected stack frame.
+If there is no current selected stack frame (for instance, if the inferior
+is not running), then @value{GDBN} will not search for a label.
+
+@cindex breakpoint at static probe point
+@item -pstap|-probe-stap @r{[}@var{objfile}:@r{[}@var{provider}:@r{]}@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes.  @xref{Static Probe Points}, for more
+information on finding and using static probes.  This form of linespec
+specifies the location of such a static probe.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable matching @var{objfile} as a regular expression are considered.
+If @var{provider} is given, then only probes from that provider are considered.
+If several probes match the spec, @value{GDBN} will insert a breakpoint at
+each one of those probes.
+@end table
+
+@subsection Explicit Locations
+@cindex explicit locations
+@anchor{Explicit Locations}
+
+@dfn{Explicit locations} allow the user to directly specify the source
+location's parameters using option-value pairs.
+
+Explicit locations are useful when several functions, labels, or
+file names have the same name (base name for files) in the program's
+sources.  In these cases, explicit locations point to the source
+line you meant more accurately and unambiguously.  Also, using
+explicit locations might be faster in large programs.
+
+For example, the linespec @samp{foo:bar} may refer to a function @code{bar}
+defined in the file named @file{foo} or the label @code{bar} in a function
+named @code{foo}.  @value{GDBN} must search either the file system or
+the symbol table to know.
+
+The list of valid explicit location options is summarized in the
+following table:
+
+@table @code
+@item -source @var{filename}
+The value specifies the source file name.  To differentiate between
+files with the same base name, prepend as many directories as is necessary
+to uniquely identify the desired file, e.g., @file{foo/bar/baz.c}.  Otherwise
+@value{GDBN} will use the first file it finds with the given base
+name.   This option requires the use of either @code{-function} or @code{-line}.
+
+@item -function @var{function}
+The value specifies the name of a function.  Operations
+on function locations unmodified by other options (such as @code{-label}
+or @code{-line}) refer to the line that begins the body of the function.
+In C, for example, this is the line with the open brace.
+
+@item -label @var{label}
+The value specifies the name of a label.  When the function
+name is not specified, the label is searched in the function of the currently
+selected stack frame.
+
+@item -line @var{number}
+The value specifies a line offset for the location.  The offset may either
+be absolute (@code{-line 3}) or relative (@code{-line +3}), depending on
+the command.  When specified without any other options, the line offset is
+relative to the current line.
+@end table
+
+Explicit location options may be abbreviated by omitting any non-unique
+trailing characters from the option name, e.g., @code{break -s main.c -li 3}.
+
+@subsection Address Locations
+@cindex address locations
+@anchor{Address Locations}
+
+@dfn{Address locations} indicate a specific program address.  They have
+the generalized form *@var{address}.
+
+For line-oriented commands, such as @code{list} and @code{edit}, this
+specifies a source line that contains @var{address}.  For @code{break} and
+other breakpoint-oriented commands, this can be used to set breakpoints in
 parts of your program which do not have debugging information or
 source files.
 
 Here @var{address} may be any expression valid in the current working
 language (@pxref{Languages, working language}) that specifies a code
 address.  In addition, as a convenience, @value{GDBN} extends the
-semantics of expressions used in locations to cover the situations
-that frequently happen during debugging.  Here are the various forms
+semantics of expressions used in locations to cover several situations
+that frequently occur during debugging.  Here are the various forms
 of @var{address}:
 
 @table @code
@@ -7610,22 +7683,6 @@ specify the function unambiguously, e.g., if there are several
 functions with identical names in different source files.
 @end table
 
-@cindex breakpoint at static probe point
-@item -pstap|-probe-stap @r{[}@var{objfile}:@r{[}@var{provider}:@r{]}@r{]}@var{name}
-The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
-applications to embed static probes.  @xref{Static Probe Points}, for more
-information on finding and using static probes.  This form of linespec
-specifies the location of such a static probe.
-
-If @var{objfile} is given, only probes coming from that shared library
-or executable matching @var{objfile} as a regular expression are considered.
-If @var{provider} is given, then only probes from that provider are considered.
-If several probes match the spec, @value{GDBN} will insert a breakpoint at
-each one of those probes.
-
-@end table
-
-
 @node Edit
 @section Editing Source Files
 @cindex editing source files
@@ -7943,9 +8000,9 @@ well as hex.
 
 @table @code
 @kindex info line
-@item info line @var{linespec}
+@item info line @var{location}
 Print the starting and ending addresses of the compiled code for
-source line @var{linespec}.  You can specify source lines in any of
+source line @var{location}.  You can specify source lines in any of
 the ways documented in @ref{Specify Location}.
 @end table
 
@@ -7963,7 +8020,7 @@ Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
 @noindent
 @cindex code address and its source line
 We can also inquire (using @code{*@var{addr}} as the form for
-@var{linespec}) what source line covers a particular address:
+@var{location}) what source line covers a particular address:
 @smallexample
 (@value{GDBP}) info line *0x63ff
 Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
@@ -8073,7 +8130,7 @@ Dump of assembler code from 0x400281 to 0x40028b:
 End of assembler dump.
 @end smallexample
 
-Addresses cannot be specified as a linespec (@pxref{Specify Location}).
+Addresses cannot be specified as a location (@pxref{Specify Location}).
 So, for example, if you want to disassemble function @code{bar}
 in file @file{foo.c}, you must type @samp{disassemble 'foo.c'::bar}
 and not @samp{disassemble foo.c:bar}.
@@ -11714,9 +11771,9 @@ argument processing and the beginning of @var{macro} for non C-like macros where
 the macro may begin with a hyphen.
 
 @kindex info macros
-@item info macros @var{linespec}
+@item info macros @var{location}
 Show all macro definitions that are in effect at the location specified
-by @var{linespec},  and describe the source location or compiler
+by @var{location},  and describe the source location or compiler
 command-line where those definitions were established.
 
 @kindex macro define
@@ -12021,12 +12078,11 @@ conditions and actions.
 @kindex trace
 @item trace @var{location}
 The @code{trace} command is very similar to the @code{break} command.
-Its argument @var{location} can be a source line, a function name, or
-an address in the target program.  @xref{Specify Location}.  The
-@code{trace} command defines a tracepoint, which is a point in the
-target program where the debugger will briefly stop, collect some
-data, and then allow the program to continue.  Setting a tracepoint or
-changing its actions takes effect immediately if the remote stub
+Its argument @var{location} can be any valid location.
+@xref{Specify Location}.  The @code{trace} command defines a tracepoint,
+which is a point in the target program where the debugger will briefly stop,
+collect some data, and then allow the program to continue.  Setting a tracepoint
+or changing its actions takes effect immediately if the remote stub
 supports the @samp{InstallInTrace} feature (@pxref{install tracepoint
 in tracing}).
 If remote stub doesn't support the @samp{InstallInTrace} feature, all
@@ -15906,14 +15962,14 @@ from the current task to the given task.
 #4  0x804aacc in un () at un.adb:5
 @end smallexample
 
-@item break @var{linespec} task @var{taskno}
-@itemx break @var{linespec} task @var{taskno} if @dots{}
+@item break @var{location} task @var{taskno}
+@itemx break @var{location} task @var{taskno} if @dots{}
 @cindex breakpoints and tasks, in Ada
 @cindex task breakpoints, in Ada
 @kindex break @dots{} task @var{taskno}@r{ (Ada)}
 These commands are like the @code{break @dots{} thread @dots{}}
 command (@pxref{Thread Stops}).  The
-@var{linespec} argument specifies source lines, as described
+@var{location} argument specifies source lines, as described
 in @ref{Specify Location}.
 
 Use the qualifier @samp{task @var{taskno}} with a breakpoint command
@@ -16841,20 +16897,17 @@ an address of your own choosing, with the following commands:
 @table @code
 @kindex jump
 @kindex j @r{(@code{jump})}
-@item jump @var{linespec}
-@itemx j @var{linespec}
-@itemx jump @var{location}
+@item jump @var{location}
 @itemx j @var{location}
-Resume execution at line @var{linespec} or at address given by
-@var{location}.  Execution stops again immediately if there is a
-breakpoint there.  @xref{Specify Location}, for a description of the
-different forms of @var{linespec} and @var{location}.  It is common
+Resume execution at @var{location}.  Execution stops again immediately
+if there is a breakpoint there.  @xref{Specify Location}, for a description
+of the different forms of @var{location}.  It is common
 practice to use the @code{tbreak} command in conjunction with
 @code{jump}.  @xref{Set Breaks, ,Setting Breakpoints}.
 
 The @code{jump} command does not change the current stack frame, or
 the stack pointer, or the contents of any memory location or any
-register other than the program counter.  If line @var{linespec} is in
+register other than the program counter.  If @var{location} is in
 a different function from the one currently executing, the results may
 be bizarre if the two functions expect different patterns of arguments or
 of local variables.  For this reason, the @code{jump} command requests
@@ -26674,6 +26727,7 @@ N.A.
 
 @subheading The @code{-break-insert} Command
 @findex -break-insert
+@anchor{-break-insert}
 
 @subsubheading Synopsis
 
@@ -26686,16 +26740,35 @@ N.A.
 @noindent
 If specified, @var{location}, can be one of:
 
-@itemize @bullet
-@item function
-@c @item +offset
-@c @item -offset
-@c @item linenum
-@item filename:linenum
-@item filename:function
-@item *address
-@end itemize
+@table @var
+@item linespec location
+A linespec location.  @xref{Linespec Locations}.
 
+@item explicit location
+An explicit location.  @sc{gdb/mi} explicit locations are
+analogous to the CLI's explicit locations using the option names
+listed below.  @xref{Explicit Locations}.
+
+@table @samp
+@item --source @var{filename}
+The source file name of the location.  This option requires the use
+of either @samp{--function} or @samp{--line}.
+
+@item --function @var{function}
+The name of a function or method.
+
+@item --label @var{label}
+The name of a label.
+
+@item --line @var{lineoffset}
+An absolute or relative line offset from the start of the location.
+@end table
+
+@item address location
+An address location, *@var{address}.  @xref{Address Locations}.
+@end table
+
+@noindent
 The possible optional parameters of this command are:
 
 @table @samp
@@ -26787,17 +26860,8 @@ times="0"@}]@}
 @end smallexample
 
 @noindent
-If specified, @var{location}, can be one of:
-
-@itemize @bullet
-@item @var{function}
-@c @item +offset
-@c @item -offset
-@c @item @var{linenum}
-@item @var{filename}:@var{linenum}
-@item @var{filename}:function
-@item *@var{address}
-@end itemize
+If supplied, @var{location} may be specified the same way as for
+the @code{-break-insert} command.  @xref{-break-insert}.
 
 The possible optional parameters of this command are:
 
diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp
index 565e339..22e6aa3 100644
--- a/gdb/testsuite/gdb.base/help.exp
+++ b/gdb/testsuite/gdb.base/help.exp
@@ -58,7 +58,7 @@ test_class_help "user-defined" {
 }
 
 # Test help of an abbreviated command.  "break" is picked at random.
-set help_breakpoint_text "Set breakpoint at specified line or function\..*"
+set help_breakpoint_text "Set breakpoint at specified location\..*"
 # test help breakpoint "b" abbreviation
 gdb_test "help b" $help_breakpoint_text "help breakpoint \"b\" abbreviation"
 # test help breakpoint "br" abbreviation

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 9/9] Explicit locations: documentation updates
  2015-05-07 18:13 ` [PATCH v4 9/9] Explicit locations: documentation updates Keith Seitz
@ 2015-05-07 18:55   ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2015-05-07 18:55 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

> From: Keith Seitz <keiths@redhat.com>
> Date: Thu, 07 May 2015 11:06:07 -0700
> 
> This patch adds documentation for explicit locations to both the
> User Manual and gdb's online help system.

Thanks.

> 	(Specifying a Location): Rewrite.  Add explanations for each
> 	location type.

You also added new subsections there.

> 	(Source and Machine Code): Use "location(s)" instead of
> 	"linespec(s)".
> 	(C Preprocessor Macros): Likewise.
> 	(Create and Delete Tracepoints): Likewise.
> 	(Extensions for Ada Tasks): Likewise.

Can we please avoid all those "likewises" and instead use the
GNU-standard ChangeLog syntax, like this:

	(Source and Machine Code, C Preprocessor Macros)
	(Create and Delete Tracepoints, Extensions for Ada Tasks): Use
	"location(s)" ...

> +@subsection Linespec Locations
> +@anchor{Linespec Locations}

I'd prefer not having subsections without @nodes.  It will require
adding a menu in the parent node, but will free you from the need to
define an @anchor.  More importantly, it will make these subsections
more easily reachable in the Info reader.

> +@dfn{Address locations} indicate a specific program address.  They have
> +the generalized form *@var{address}.
                        ^^^^^^^^^^^^^^
This should be in @code, as in @code{*@var{address}}.

> +@item address location
> +An address location, *@var{address}.  @xref{Address Locations}.

Same here.

OK with these fixed.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location"
  2015-05-07 18:06 ` [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
@ 2015-05-17 20:10   ` Doug Evans
  0 siblings, 0 replies; 33+ messages in thread
From: Doug Evans @ 2015-05-17 20:10 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch renames all occurrances of "addr_string" and "address
> string" in the breakpoint/linespec APIs.  This will emphasize the
> change from address strings used in setting breakpoints (et al) to the
> new locations-based API introduced in subsequent patches.
>
> gdb/ChangeLog:
>
> 	* breakpoint.h (struct breakpoint_ops) <create_sals_from_address>:
> 	Renamed to create_sals_from_location.
> 	<decode_linespec>: Renamed to decode_location.
> 	Update all callers.
> 	* breakpoint.c (create_sals_from_address_default): Renamed to ...
> 	(create_sals_from_location_default): ... this.
> 	(addr_string_to_sals): Renamed to ...
> 	(location_to_sals): ... this.
> 	(decode_linespec_default): Renamed to ...
> 	(decode_location_default): ... this.
> 	(base_breakpoint_create_sals_from_address): Renamed to ...
> 	(base_breakpoint_create_sals_from_location): ... this.
> 	(bkpt_create_sals_from_address): Renamed to ...
> 	(bkpt_create_sals_from_location): ... this.
> 	(bkpt_decode_linespec): Renamed to ...
> 	(bkpt_decode_location): ... this.
> 	(bkpt_probe_create_sals_from_address): Renamed to ...
> 	(bkpt_probe_create_sals_from_location): ... this.
> 	(tracepoint_create_sals_from_address): Renamed to ...
> 	(tracepoint_create_sals_from_location): ... this.
> 	(tracepoint_decode_linespec): Renamed to ...
> 	(tracepoint_decode_location): ... this.
> 	(tracepoint_probe_create_sals_from_address): Renamed to ...
> 	(tracepoint_probe_create_sals_from_location): ... this.
> 	(tracepoint_probe_decode_linespec): Renamed to ...
> 	(tracepoint_probe_decode_location): ... this.
> 	(strace_marker_create_sals_from_address): Renamed to ...
> 	(strace_marker_create_sals_from_location): ... this.
> 	(decode_linespec_default): Renamed to ...
> 	(decode_location_default): ... this.

LGTM

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API
  2015-05-07 18:05 ` [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
@ 2015-05-17 20:54   ` Doug Evans
  2015-05-19 20:41     ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Doug Evans @ 2015-05-17 20:54 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch introduces the new breakpoint/"linespec" API based on
> a new struct event_location.  This API currently only supports
> traditional linespecs, maintaining the status quo of the code base.
> Future patches will add additional functionality for other location
> types such as address locations.

Hi. Just a couple of nits and a couple of questions.
I wrote down a question for myself below.
I haven't read the entire series yet.

>
> gdb/ChangeLog:
>
> 	* Makefile.in (SFILES): Add location.c.
> 	(HFILES_NO_SRCDIR): Add location.h.
> 	(COMMON_OBS): Add location.o.
> 	* linespec.c (linespec_lex_to_end): New function.
> 	* linespec.c (linespec_lex_to_end): Declare.

typo: linespec.h

> 	* location.c: New file.
> 	* location.h: New file.
>...
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 95104ef..0a51564 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -851,7 +851,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
>  	inline-frame.c \
>  	interps.c \
>  	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c jv-varobj.c \
> -	language.c linespec.c minidebug.c \
> +	language.c linespec.c location.c minidebug.c \
>  	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
>  	macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
>  	mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
> @@ -937,7 +937,7 @@ mi/mi-out.h mi/mi-main.h mi/mi-common.h mi/mi-cmds.h linux-nat.h \
>  complaints.h gdb_proc_service.h gdb_regex.h xtensa-tdep.h inf-loop.h \
>  common/gdb_wait.h common/gdb_assert.h solib.h ppc-tdep.h cp-support.h glibc-tdep.h \
>  interps.h auxv.h gdbcmd.h tramp-frame.h mipsnbsd-tdep.h	\
> -amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \
> +amd64-linux-tdep.h linespec.h location.h i387-tdep.h mn10300-tdep.h \
>  sparc64-tdep.h monitor.h ppcobsd-tdep.h srec.h \
>  coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
>  m68k-tdep.h spu-tdep.h jv-lang.h environ.h amd64-tdep.h \
> @@ -1021,7 +1021,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
>  	source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
>  	block.o symtab.o psymtab.o symfile.o symfile-debug.o symmisc.o \
>  	linespec.o dictionary.o \
> -	infcall.o \
> +	location.o infcall.o \
>  	infcmd.o infrun.o \
>  	expprint.o environ.o stack.o thread.o \
>  	exceptions.o \
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index d2089b5..a480be1 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -2435,6 +2435,61 @@ linespec_parser_delete (void *arg)
>    linespec_state_destructor (PARSER_STATE (parser));
>  }
>  
> +/* See description in linespec.h.  */
> +
> +void
> +linespec_lex_to_end (char **stringp)
> +{
> +  linespec_parser parser;
> +  struct cleanup *cleanup;
> +  linespec_token token;
> +  volatile struct gdb_exception e;
> +  const char *orig;
> +
> +  if (stringp == NULL || *stringp == NULL)
> +    return;
> +
> +  linespec_parser_new (&parser, 0, current_language, NULL, 0, NULL);
> +  cleanup = make_cleanup (linespec_parser_delete, &parser);
> +  parser.lexer.saved_arg = *stringp;
> +  PARSER_STREAM (&parser) = orig = *stringp;
> +
> +  TRY
> +    {
> +      do
> +	{
> +	  /* Stop before any comma tokens;  we need it to keep it
> +	     as the next token in the string.  */
> +	  token = linespec_lexer_peek_token (&parser);
> +	  if (token.type == LSTOKEN_COMMA)
> +	    break;
> +
> +	  /* For addresses advance the parser stream past
> +	     any parsed input and stop lexing.  */
> +	  if (token.type == LSTOKEN_STRING
> +	      && *LS_TOKEN_STOKEN (token).ptr == '*')
> +	    {
> +	      const char *arg;
> +
> +	      arg = *stringp;
> +	      (void) linespec_expression_to_pc (&arg);
> +	      PARSER_STREAM (&parser) = arg;
> +	      break;
> +	    }
> +
> +	  token = linespec_lexer_consume_token (&parser);
> +	}
> +      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
> +    }
> +  CATCH (e, RETURN_MASK_ERROR)
> +    {

I'm guessing I'm missing something here.
Is the intent to ignore errors here?

> +    }
> +  END_CATCH
> +
> +  *stringp += PARSER_STREAM (&parser) - orig;
> +  do_cleanups (cleanup);
> +}
> +
>  /* See linespec.h.  */
>  
>  void
> diff --git a/gdb/linespec.h b/gdb/linespec.h
> index 7e66024..77ec46d 100644
> --- a/gdb/linespec.h
> +++ b/gdb/linespec.h
> @@ -156,4 +156,9 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
>     the keyword.  If not, return NULL.  */
>  
>  extern const char *linespec_lexer_lex_keyword (const char *p);
> +
> +/* Find the end of the (first) linespec pointed to by *STRINGP.
> +   STRINGP will be advanced to this point.  */
> +
> +extern void linespec_lex_to_end (char **stringp);
>  #endif /* defined (LINESPEC_H) */
> diff --git a/gdb/location.c b/gdb/location.c
> new file mode 100644
> index 0000000..39e09c1
> --- /dev/null
> +++ b/gdb/location.c
> @@ -0,0 +1,234 @@
> +/* Data structures and API for event locations in GDB.
> +   Copyright (C) 2013-2015 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#include "defs.h"
> +#include "gdb_assert.h"
> +#include "location.h"
> +#include "symtab.h"
> +#include "language.h"
> +#include "linespec.h"
> +#include "cli/cli-utils.h"
> +#include "probe.h"
> +
> +#include <ctype.h>
> +#include <string.h>
> +
> +/* An event location used to set a stop event in the inferior.
> +   This structure is an amalgam of the various ways
> +   to specify where a stop event should be set.  */
> +
> +struct event_location
> +{
> +  /* The type of this breakpoint specification.  */
> +  enum event_location_type type;
> +#define EL_TYPE(PTR) (PTR)->type
> +
> +  union
> +  {
> +    /* A generic "this is a string specification" for a location.
> +       This representation is used by both "normal" linespecs and
> +       probes.  */
> +    char *addr_string;
> +#define EL_LINESPEC(PTR) ((PTR)->u.addr_string)
> +  } u;
> +
> +  /* Cached string representation of this location.  This is used, e.g., to
> +     save stop event locations to file.  Malloc'd.  */
> +  char *as_string;
> +#define EL_STRING(PTR) ((PTR)->as_string)
> +};
> +
> +/* See description in location.h.  */
> +
> +enum event_location_type
> +event_location_type (const struct event_location *location)
> +{
> +  return EL_TYPE (location);
> +}
> +
> +/* See description in location.h.  */
> +
> +struct event_location *
> +new_linespec_location (char **linespec)
> +{
> +  struct event_location *location;
> +
> +  location = XCNEW (struct event_location);
> +  EL_TYPE (location) = LINESPEC_LOCATION;
> +  if (*linespec != NULL)
> +    {
> +      char *p;
> +      char *orig = *linespec;
> +
> +      linespec_lex_to_end (linespec);
> +      p = remove_trailing_whitespace (orig, *linespec);
> +      if ((p - orig) > 0)
> +	EL_LINESPEC (location) = savestring (orig, p - orig);
> +    }
> +  return location;
> +}
> +
> +/* See description in location.h.  */
> +
> +const char *
> +get_linespec_location (const struct event_location *location)
> +{
> +  gdb_assert (EL_TYPE (location) == LINESPEC_LOCATION);
> +  return EL_LINESPEC (location);
> +}
> +
> +/* See description in location.h.  */
> +
> +struct event_location *
> +copy_event_location (const struct event_location *src)
> +{
> +  struct event_location *dst;
> +
> +  dst = XCNEW (struct event_location);
> +  EL_TYPE (dst) = EL_TYPE (src);
> +  if (EL_STRING (src) != NULL)
> +    EL_STRING (dst) = xstrdup (EL_STRING (src));
> +
> +  switch (EL_TYPE (src))
> +    {
> +    case LINESPEC_LOCATION:
> +      if (EL_LINESPEC (src) != NULL)
> +	EL_LINESPEC (dst) = xstrdup (EL_LINESPEC (src));
> +      break;
> +
> +    default:
> +      gdb_assert_not_reached ("unknown event location type");
> +    }
> +
> +  return dst;
> +}
> +
> +/* A cleanup function for struct event_location.  */
> +
> +static void
> +delete_event_location_cleanup (void *data)
> +{
> +  struct event_location *location = (struct event_location *) data;
> +
> +  delete_event_location (location);
> +}
> +
> +/* See description in location.h.  */
> +
> +struct cleanup *
> +make_cleanup_delete_event_location (struct event_location *location)
> +{
> +  return make_cleanup (delete_event_location_cleanup, location);
> +}
> +
> +/* See description in location.h.  */
> +
> +void
> +delete_event_location (struct event_location *location)
> +{
> +  if (location != NULL)
> +    {
> +      xfree (EL_STRING (location));
> +
> +      switch (EL_TYPE (location))
> +	{
> +	case LINESPEC_LOCATION:
> +	  xfree (EL_LINESPEC (location));
> +	  break;
> +
> +	default:
> +	  gdb_assert_not_reached ("unknown event location type");
> +	}
> +
> +      xfree (location);
> +    }
> +}
> +
> +/* See description in location.h.  */
> +
> +char *
> +event_location_to_string_const (const struct event_location *location)
> +{
> +  char *result = NULL;
> +
> +  if (EL_STRING (location) != NULL)
> +    return xstrdup (EL_STRING (location));
> +
> +  switch (EL_TYPE (location))
> +    {
> +    case LINESPEC_LOCATION:
> +      if (EL_LINESPEC (location) != NULL)
> +	result = xstrdup (EL_LINESPEC (location));
> +      break;
> +
> +    default:
> +      gdb_assert_not_reached ("unknown event location type");
> +    }
> +
> +  return result;
> +}
> +
> +/* See description in location.h.  */
> +
> +const char *
> +event_location_to_string (struct event_location *location)
> +{
> +  /* Cache a copy of the string representation.  */
> +  if (EL_STRING (location) == NULL)
> +    EL_STRING (location) = event_location_to_string_const (location);
> +
> +  return EL_STRING (location);
> +}
> +
> +/* See description in location.h.  */
> +
> +struct event_location *
> +string_to_event_location (char **stringp,
> +			  const struct language_defn *language)
> +{
> +  struct event_location *location;
> +
> +  location = new_linespec_location (stringp);
> +  return location;
> +}
> +
> +/* See description in location.h.  */
> +
> +int
> +event_location_empty_p (const struct event_location *location)
> +{
> +  switch (EL_TYPE (location))
> +    {
> +    case LINESPEC_LOCATION:
> +      /* Linespecs are never "empty."  (NULL is a valid linespec)  */
> +      return 0;
> +
> +    default:
> +      gdb_assert_not_reached ("unknown event location type");
> +    }
> +}
> +
> +/* See description in location.h.  */
> +
> +void
> +set_event_location_string (struct event_location *location,
> +			   const char *string)
> +{
> +  xfree (EL_STRING (location));
> +  EL_STRING (location) = string == NULL ?  NULL : xstrdup (string);
> +}
> diff --git a/gdb/location.h b/gdb/location.h
> new file mode 100644
> index 0000000..992f21e
> --- /dev/null
> +++ b/gdb/location.h
> @@ -0,0 +1,113 @@
> +/* Data structures and API for event locations in GDB.
> +   Copyright (C) 2013-2015 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   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/>.  */
> +
> +#ifndef LOCATIONS_H
> +#define LOCATIONS_H 1
> +
> +struct language_defn;
> +struct event_location;
> +
> +/* An enumeration of the various ways to specify a stop event
> +   location (used with create_breakpoint).  */
> +
> +enum event_location_type
> +{
> +  /* A traditional linespec.  */
> +  LINESPEC_LOCATION
> +};
> +
> +/* Return the type of the given event location.  */
> +
> +extern enum event_location_type
> +  event_location_type (const struct event_location *);
> +
> +/* Return a string representation of the LOCATION.
> +   This function may return NULL for unspecified linespecs,
> +   e.g, LOCATION_LINESPEC and addr_string is NULL.
> +
> +   The result is cached in LOCATION.  */
> +
> +extern const char *
> +  event_location_to_string (struct event_location *location);
> +
> +/* A const version of event_location_to_string that will not cache
> +   the resulting string representation.  The result is malloc'd
> +   and must be freed by the caller.  */
> +
> +extern char *
> +  event_location_to_string_const (const struct event_location *location);

Note to self: Do we need both non-const and const versions?
[e.g., treat cached value as mutable in c++ sense?]

> +
> +/* Create a new linespec location.  The return result is malloc'd
> +   and should be freed with delete_event_location.  */
> +
> +extern struct event_location *
> +  new_linespec_location (char **linespec);
> +
> +/* Return the linespec location (a string) of the given event_location
> +   (which must be of type LINESPEC_LOCATION).  */
> +
> +extern const char *
> +  get_linespec_location (const struct event_location *location);
> +
> +/* Free an event location and any associated data.  */
> +
> +extern void delete_event_location (struct event_location *location);
> +
> +/* Make a cleanup to free LOCATION.  */
> +
> +extern struct cleanup *
> +  make_cleanup_delete_event_location (struct event_location *location);
> +
> +/* Return a copy of the given SRC location.  */
> +
> +extern struct event_location *
> +  copy_event_location (const struct event_location *src);
> +
> +/* Allocate and "copy" the opaque struct event_location.  This is used
> +   when decoding locations which must parse their inputs.  The return result
> +   should be freed.  */
> +
> +extern struct event_location *
> +  copy_event_location_tmp (const struct event_location *src);

This function doesn't exist in this patch.

> +
> +/* Attempt to convert the input string in *ARGP into an event location.
> +   ARGP is advanced past any processed input.  Returns a event_location

nit: an 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.
> +
> +   The return result must be freed with delete_event_location.  */
> +
> +extern struct event_location *
> +  string_to_event_location (char **argp,
> +			    const struct language_defn *langauge);
> +
> +/* A convenience function for testing for unset locations.  */
> +
> +extern int event_location_empty_p (const struct event_location *location);
> +
> +/* Set the location's string representation.  If STRING is NULL, clear
> +   the string representation.  */
> +
> +extern void
> +  set_event_location_string (struct event_location *location,
> +			     const char *string);
> +#endif /* LOCATIONS_H */

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 3/9] Explicit locations: use new location API
  2015-05-07 18:06 ` [PATCH v4 3/9] Explicit locations: use new location API Keith Seitz
@ 2015-05-18  5:21   ` Doug Evans
  2015-05-19 21:30     ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Doug Evans @ 2015-05-18  5:21 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch converts the code base to use the new struct event_location
> API being introduced. This patch preserves the current functionality and
> adds no new features.
>
> The "big picture" API usage introduced by this patch may be illustrated
> with a simple exmaple. Where previously developers would write:
>
> void
> my_command (char *arg, int from_tty)
> {
>    create_breakpoint (..., arg, ...);
>    ...
> }
>
> one now uses:
>
> void
> my_command (char *arg, int from_tty)
> {
>    struct event_locaiton *location;
>    struct cleanup *back_to;
>
>    location = string_to_event_locaiton (&arg, ...);
>    back_to = make_cleanup_delete_event_location (location);
>    create_breakpoint (..., location, ...);
>    do_cleanups (back_to);
> }
>
> Linespec-decoding functions (now called location-decoding) such as
> decode_line_full no longer skip argument pointers over processed input.
> That functionality has been moved into string_to_event_location as
> demonstrated above.
>
> gdb/ChangeLog
>
> 	* ax-gdb.c: Include location.h.
> 	(agent_command_1) Use linespec location instead of address
> 	string.
> 	* break-catch-throw.c: Include location.h.
> 	(re_set_exception_catchpoint): Use linespec locations instead
> 	of address strings.
> 	* breakpoint.c: Include location.h.
> 	(create_overlay_event_breakpoint): Use linespec location
> 	instead of address string.
> 	(create_longjmp_master_breakpoint): Likewise.
> 	(create_std_terminate_master_breakpoint): Likewise.
> 	(create_exception_master_breakpoint): Likewise.
> 	(update_breakpoints_after_exec): Likewise.
> 	(print_breakpoint_location): Use locations and
> 	event_location_to_string.
> 	(print_one_breakpoint_location): Likewise.
> 	(init_raw_breakpoint_without_location): Initialize
> 	b->location.
> 	(create_thread_event_breakpoint): Use linespec location instead of
> 	address string.
> 	(init_breakpoint_sal): Likewise.
> 	Only save extra_string if it is non-NULL and not the empty string.
> 	Use event_location_to_string instead of `addr_string'.
> 	Constify `p' and `endp'.
> 	Use skip_spaces_const/skip_space_const instead of non-const versions.
> 	Copy the location into the breakpoint.
> 	If LOCATION is NULL, save the breakpoint address as a linespec location
> 	instead of an address string.
> 	(create_breakpoint_sal): Change `addr_string' parameter to a struct
> 	event_location. All uses updated.
> 	(create_breakpoints_sal): Likewise for local variable `addr_string'.
> 	(parse_breakpoint_sals): Use locations instead of address strings.
> 	Remove check for empty linespec with conditional.
> 	Refactor.
> 	(decode_static_tracepoint_spec): Make argument const and update
> 	function.
> 	(create_breakpoint): Change `arg' to a struct event_location and
> 	rename.
> 	Remove `copy_arg' and `addr_start'.
> 	If EXTRA_STRING is empty, set it to NULL.
> 	Don't populate `canonical' for pending breakpoints.
> 	Pass `extra_string' to find_condition_and_thread.
> 	Clear `extra_string' if `rest' was NULL.
> 	Do not error with "garbage after location" if setting a dprintf
> 	breakpoint.
> 	Copy the location into the breakpoint instead of an address string.
> 	For pending breakpoints, append `extra_string' to the location's
> 	string representation and make a private copy of `extra_string' for
> 	the breakpoint.
> 	(break_command_1): Use string_to_event_location and pass this to
> 	create_breakpoint instead of an address string.
> 	Check against `arg_cp' for a probe linespec.
> 	(dprintf_command): Use string_to_event_location and pass this to
> 	create_breakpoint instead of an address string.
> 	(print_recreate_ranged_breakpoint): Use event_location_to_string
> 	instead of address strings.
> 	(break_range_command): Use locations instead of address strings.
> 	(until_break_command): Likewise.
> 	(init_ada_exception_breakpoint): Likewise.
> 	(say_where): Likewise.
> 	(base_breakpoint_dtor): Delete `location' and `location_range_end' of
> 	the breakpoint.
> 	(base_breakpoint_create_sals_from_location): Use struct event_location
> 	instead of address string.
> 	Remove `addr_start' and `copy_arg' parameters.
> 	(base_breakpoint_decode_location): Use struct event_location instead of
> 	address string.
> 	(bkpt_re_set): Use locations instead of address strings.
> 	Use event_location_empty_p to check for unset location.
> 	(bkpt_print_recreate): Use event_location_to_string instead of
> 	an address string.
> 	(bkpt_create_sals_from_location): Use struct event_location instead of
> 	address string.
> 	(bkpt_decode_location): Likewise.
> 	(bkpt_probe_create_sals_from_location): Likewise.
> 	(bkpt_probe_decode_location): Use struct event_location instead of
> 	address string.
> 	(tracepoint_print_recreate): Use event_location_to_string to
> 	recreate the tracepoint.
> 	(tracepoint_create_sals_from_location): Use struct event_location
> 	instead of address string.
> 	(tracepoint_decode_location): Likewise.
> 	(tracepoint_probe_create_sals_from_location): Likewise.
> 	(tracepoint_probe_decode_location): Likewise.
> 	(dprintf_print_recreate): Use event_location_to_string to recreate
> 	the dprintf.
> 	(strace_marker_create_sals_from_location): Use struct event_location
> 	instead of address string.
> 	(strace_marker_create_breakpoints_sal): Likewise.
> 	(strace_marker_decode_location): Likewise.
> 	(update_static_tracepoint): Likewise.
> 	(location_to_sals): Likewise.
> 	Pass `extra_string' to find_condition_and_thread.
> 	For newly resolved pending breakpoint locations, clear the location's
> 	string representation.
> 	(breakpoint_re_set_default): Use locations instead of address
> 	strings.
> 	(create_sals_from_location_default): Likewise.
> 	(decode_location_default): Use locations instead of address strings.
> 	(trace_command): Use locations instead of address strings.
> 	(ftrace_command): Likewise.
> 	(strace_command): Likewise.
> 	(create_tracepoint_from_upload): Likewise.
> 	* breakpoint.h (struct breakpoint_ops) <create_sals_from_location>:
> 	Use struct event_location instead of address string.
> 	Update all uses.
> 	<decode_location>: Likewise.
> 	(struct breakpoint) <addr_string>: Change to struct event_location
> 	and rename `location'.
> 	<addr_string_range_end>: Change to struct event_location and rename
> 	`location_range_end'.
> 	(create_breakpoint): Use struct event_location instead of address
> 	string.
> 	* cli/cli-cmds.c: Include location.h.
> 	(edit_command): Use locations instead of address strings.
> 	(list_command): Likewise.
> 	* elfread.c: Include location.h.
> 	(elf_gnu_ifunc_resolver_return_stop): Use event_location_to_string.
> 	* guile/scm-breakpoint.c: Include location.h.
> 	(bpscm_print_breakpoint_smob): Use event_location_to_string.
> 	(gdbscm_register_breakpoint): Use locations instead of address
> 	strings.
> 	* linespec.c: Include location.h.
> 	(struct ls_parser) <stream>: Change to const char *.
> 	(PARSER_STREAM): Update.
> 	(lionespec_lexer_lex_keyword): According to find_condition_and_thread,
> 	keywords must be followed by whitespace.
> 	(canonicalize_linespec): Save a linespec location into `canonical'.
> 	Save a canonical linespec into `canonical'.
> 	(parse_linespec): Change `argptr' to const char * and rename `arg'.
> 	All uses updated.
> 	Update function description.
> 	(linespec_parser_new): Initialize `parser'.
> 	Update initialization of  parsing stream.
> 	(event_location_to_sals): New function.
> 	(decode_line_full): Change `argptr' to a struct event_location and
> 	rename it `location'.
> 	Use locations instead of address strings.
> 	Call event_location_to_sals instead of parse_linespec.
> 	(decode_line_1): Likewise.
> 	(decode_line_with_current_source): Use locations instead of
> 	address strings.
> 	(decode_line_with_last_displayed): Likewise.
> 	(decode_objc): Likewise.
> 	Change `argptr' to const char * and rename `arg'.
> 	(destroy_linespec_result): Delete the linespec result's location
> 	instead of freeing the address string.
> 	* linespec.h (struct linespec_result) <addr_string>: Change to
> 	struct event_location and rename to ...
> 	<location>: ... this.
> 	(decode_line_1): Change `argptr' to struct event_location.
> 	All callers updated.
> 	(decode_line_full): Likewise.
> 	* mi/mi-cmd-break.c: Include language.h, location.h, and linespec.h.
> 	(mi_cmd_break_insert_1): Use locations instead of address strings.
> 	Throw an error if there was "garbage" at the end of the specified
> 	linespec.
> 	* probe.c: Include location.h.
> 	(parse_probes): Change `argptr' to struct event_location.
> 	Use event locations instead of address strings.
> 	* probe.h (parse_probes): Change `argptr' to struct event_location.
> 	* python/py-breakpoint.c: Include location.h.
> 	(bppy_get_location): Constify local variable `str'.
> 	Use event_location_to_string.
> 	(bppy_init): Use locations instead of address strings.
> 	* python/py-finishbreakpoint.c: Include location.h.
> 	(bpfinishpy_init): Remove local variable `addr_str'.
> 	Use locations instead of address strings.
> 	* python/python.c: Include location.h.
> 	(gdbpy_decode_line): Use locations instead of address strings.
> 	* remote.c: Include location.h.
> 	(remote_download_tracepoint): Use locations instead of address
> 	strings.
> 	* spu-tdep.c: Include location.h.
> 	(spu_catch_start): Remove local variable `buf'.
> 	Use locations instead of address strings.
> 	* tracepoint.c: Include location.h.
> 	(scope_info): Use locations instead of address strings.
> 	(encode_source_string): Constify parameter `src'.
> 	* tracepoint.h (encode_source_string): Likewise.
>...
> diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
> index 7a9d1e7..2fd5a1a 100644
> --- a/gdb/ax-gdb.c
> +++ b/gdb/ax-gdb.c
> @@ -40,6 +40,7 @@
>  #include "arch-utils.h"
>  #include "cli/cli-utils.h"
>  #include "linespec.h"
> +#include "location.h"
>  #include "objfiles.h"
>  
>  #include "valprint.h"
> @@ -2642,13 +2643,16 @@ agent_command_1 (char *exp, int eval)
>        int ix;
>        struct linespec_sals *iter;
>        struct cleanup *old_chain;
> +      struct event_location *location;
>  
>        exp = skip_spaces (exp);
>        init_linespec_result (&canonical);
> -      decode_line_full (&exp, DECODE_LINE_FUNFIRSTLINE,
> +      location = new_linespec_location (&exp);
> +      old_chain = make_cleanup_delete_event_location (location);
> +      decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
>  			(struct symtab *) NULL, 0, &canonical,
>  			NULL, NULL);
> -      old_chain = make_cleanup_destroy_linespec_result (&canonical);
> +      make_cleanup_destroy_linespec_result (&canonical);
>        exp = skip_spaces (exp);
>        if (exp[0] == ',')
>          {
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index 927176f..9449aa5 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -35,6 +35,7 @@
>  #include "cp-abi.h"
>  #include "gdb_regex.h"
>  #include "cp-support.h"
> +#include "location.h"
>  
>  /* Enums for exception-handling support.  */
>  enum exception_event_kind
> @@ -210,25 +211,31 @@ re_set_exception_catchpoint (struct breakpoint *self)
>    struct symtabs_and_lines sals_end = {0};
>    struct cleanup *cleanup;
>    enum exception_event_kind kind = classify_exception_breakpoint (self);
> +  struct event_location *location;
>  
>    /* We first try to use the probe interface.  */
>    TRY
>      {
>        char *spec = ASTRDUP (exception_functions[kind].probe);
>  

Not something to be done with this patch (let's reach
closure and get this sucker checked in :-)),
but IWBN to have an API where we didn't have to do the
ASTRDUP.  E.g., have new_linespec_location_const or some such.

> -      sals = parse_probes (&spec, NULL);
> +      location = new_linespec_location (&spec);
> +      cleanup = make_cleanup_delete_event_location (location);
> +      sals = parse_probes (location, NULL);
> +      do_cleanups (cleanup);
>      }
>  
>    CATCH (e, RETURN_MASK_ERROR)
>      {
> -
>        /* Using the probe interface failed.  Let's fallback to the normal
>  	 catchpoint mode.  */
>        TRY
>  	{
>  	  char *spec = ASTRDUP (exception_functions[kind].function);
>  
> -	  self->ops->decode_location (self, &spec, &sals);
> +	  location = new_linespec_location (&spec);
> +	  cleanup = make_cleanup_delete_event_location (location);
> +	  self->ops->decode_location (self, location, &sals);
> +	  do_cleanups (cleanup);
>  	}
>        CATCH (ex, RETURN_MASK_ERROR)
>  	{
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 31b1f82..549bfd0 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -67,6 +67,7 @@
>  #include "dummy-frame.h"
>  #include "interps.h"
>  #include "format.h"
> +#include "location.h"
>  
>  /* readline include files */
>  #include "readline/readline.h"
> @@ -108,10 +109,10 @@ static int breakpoint_re_set_one (void *);
>  
>  static void breakpoint_re_set_default (struct breakpoint *);
>  
> -static void create_sals_from_location_default (char **,
> -					       struct linespec_result *,
> -					       enum bptype, char *,
> -					       char **);
> +static void
> +  create_sals_from_location_default (const struct event_location *location,
> +				     struct linespec_result *canonical,
> +				     enum bptype type_wanted);
>  
>  static void create_breakpoints_sal_default (struct gdbarch *,
>  					    struct linespec_result *,
> @@ -121,8 +122,9 @@ static void create_breakpoints_sal_default (struct gdbarch *,
>  					    const struct breakpoint_ops *,
>  					    int, int, int, unsigned);
>  
> -static void decode_location_default (struct breakpoint *, char **,
> -				     struct symtabs_and_lines *);
> +static void decode_location_default (struct breakpoint *b,
> +				     const struct event_location *location,
> +				     struct symtabs_and_lines *sals);
>  
>  static void clear_command (char *, int);
>  
> @@ -3412,6 +3414,7 @@ create_overlay_event_breakpoint (void)
>        struct breakpoint *b;
>        struct breakpoint_objfile_data *bp_objfile_data;
>        CORE_ADDR addr;
> +      char *p;
>  
>        bp_objfile_data = get_breakpoint_objfile_data (objfile);
>  
> @@ -3436,7 +3439,8 @@ create_overlay_event_breakpoint (void)
>        b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
>                                        bp_overlay_event,
>  				      &internal_breakpoint_ops);
> -      b->addr_string = xstrdup (func_name);
> +      p = ASTRDUP (func_name);
> +      b->location = new_linespec_location (&p);
>  
>        if (overlay_debugging == ovly_auto)
>          {
> @@ -3503,6 +3507,7 @@ create_longjmp_master_breakpoint (void)
>  	  int i;
>  	  struct probe *probe;
>  	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
> +	  char *p;
>  
>  	  for (i = 0;
>  	       VEC_iterate (probe_p,
> @@ -3517,7 +3522,8 @@ create_longjmp_master_breakpoint (void)
>  								 objfile),
>  					      bp_longjmp_master,
>  					      &internal_breakpoint_ops);
> -	      b->addr_string = xstrdup ("-probe-stap libc:longjmp");
> +	      p = ASTRDUP ("-probe-stap libc:longjmp");
> +	      b->location = new_linespec_location (&p);
>  	      b->enable_state = bp_disabled;
>  	    }
>  
> @@ -3532,6 +3538,7 @@ create_longjmp_master_breakpoint (void)
>  	  struct breakpoint *b;
>  	  const char *func_name;
>  	  CORE_ADDR addr;
> +	  char *p;
>  
>  	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
>  	    continue;
> @@ -3554,7 +3561,8 @@ create_longjmp_master_breakpoint (void)
>  	  addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
>  	  b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
>  					  &internal_breakpoint_ops);
> -	  b->addr_string = xstrdup (func_name);
> +	  p = ASTRDUP (func_name);
> +	  b->location = new_linespec_location (&p);
>  	  b->enable_state = bp_disabled;
>  	}
>      }
> @@ -3585,6 +3593,7 @@ create_std_terminate_master_breakpoint (void)
>      {
>        struct breakpoint *b;
>        struct breakpoint_objfile_data *bp_objfile_data;
> +      char *p;
>  
>        bp_objfile_data = get_breakpoint_objfile_data (objfile);
>  
> @@ -3610,7 +3619,8 @@ create_std_terminate_master_breakpoint (void)
>        b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
>                                        bp_std_terminate_master,
>  				      &internal_breakpoint_ops);
> -      b->addr_string = xstrdup (func_name);
> +      p = ASTRDUP (func_name);
> +      b->location = new_linespec_location (&p);
>        b->enable_state = bp_disabled;
>      }
>    }
> @@ -3634,6 +3644,7 @@ create_exception_master_breakpoint (void)
>        struct gdbarch *gdbarch;
>        struct breakpoint_objfile_data *bp_objfile_data;
>        CORE_ADDR addr;
> +      char *p;
>  
>        bp_objfile_data = get_breakpoint_objfile_data (objfile);
>  
> @@ -3674,13 +3685,15 @@ create_exception_master_breakpoint (void)
>  	       ++i)
>  	    {
>  	      struct breakpoint *b;
> +	      char *p;
>  
>  	      b = create_internal_breakpoint (gdbarch,
>  					      get_probe_address (probe,
>  								 objfile),
>  					      bp_exception_master,
>  					      &internal_breakpoint_ops);
> -	      b->addr_string = xstrdup ("-probe-stap libgcc:unwind");
> +	      p = ASTRDUP ("-probe-stap libgcc:unwind");
> +	      b->location = new_linespec_location (&p);
>  	      b->enable_state = bp_disabled;
>  	    }
>  
> @@ -3713,7 +3726,8 @@ create_exception_master_breakpoint (void)
>  						 &current_target);
>        b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
>  				      &internal_breakpoint_ops);
> -      b->addr_string = xstrdup (func_name);
> +      p = ASTRDUP (func_name);
> +      b->location = new_linespec_location (&p);
>        b->enable_state = bp_disabled;
>      }
>  
> @@ -3834,7 +3848,7 @@ update_breakpoints_after_exec (void)
>      /* Without a symbolic address, we have little hope of the
>         pre-exec() address meaning the same thing in the post-exec()
>         a.out.  */
> -    if (b->addr_string == NULL)
> +    if (event_location_empty_p (b->location))
>        {
>  	delete_breakpoint (b);
>  	continue;
> @@ -6021,7 +6035,8 @@ print_breakpoint_location (struct breakpoint *b,
>      set_current_program_space (loc->pspace);
>  
>    if (b->display_canonical)
> -    ui_out_field_string (uiout, "what", b->addr_string);
> +    ui_out_field_string (uiout, "what",
> +			 event_location_to_string (b->location));
>    else if (loc && loc->symtab)
>      {
>        struct symbol *sym 
> @@ -6057,7 +6072,8 @@ print_breakpoint_location (struct breakpoint *b,
>        do_cleanups (stb_chain);
>      }
>    else
> -    ui_out_field_string (uiout, "pending", b->addr_string);
> +    ui_out_field_string (uiout, "pending",
> +			 event_location_to_string (b->location));
>  
>    if (loc && is_breakpoint (b)
>        && breakpoint_condition_evaluation_mode () == condition_evaluation_target
> @@ -6526,8 +6542,10 @@ print_one_breakpoint_location (struct breakpoint *b,
>  
>  	  ui_out_field_string (uiout, "original-location", w->exp_string);
>  	}
> -      else if (b->addr_string)
> -	ui_out_field_string (uiout, "original-location", b->addr_string);
> +      else if (b->location != NULL
> +	       && event_location_to_string (b->location) != NULL)
> +	ui_out_field_string (uiout, "original-location",
> +			     event_location_to_string (b->location));
>      }
>  }
>  
> @@ -7297,6 +7315,7 @@ init_raw_breakpoint_without_location (struct breakpoint *b,
>    b->condition_not_parsed = 0;
>    b->py_bp_object = NULL;
>    b->related_breakpoint = b;
> +  b->location = NULL;
>  }
>  
>  /* Helper to set_raw_breakpoint below.  Creates a breakpoint
> @@ -7637,15 +7656,19 @@ delete_std_terminate_breakpoint (void)
>  struct breakpoint *
>  create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
>  {
> +  char *tmp;
>    struct breakpoint *b;
> +  struct cleanup *cleanup;
>  
>    b = create_internal_breakpoint (gdbarch, address, bp_thread_event,
>  				  &internal_breakpoint_ops);
>  
>    b->enable_state = bp_enabled;
> -  /* addr_string has to be used or breakpoint_re_set will delete me.  */
> -  b->addr_string
> -    = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
> +  /* location has to be used or breakpoint_re_set will delete me.  */
> +  tmp = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
> +  cleanup = make_cleanup (xfree, tmp);
> +  b->location = new_linespec_location (&tmp);
> +  do_cleanups (cleanup);
>  
>    update_global_location_list_nothrow (UGLL_MAY_INSERT);
>  
> @@ -9083,13 +9106,14 @@ update_dprintf_commands (char *args, int from_tty,
>      }
>  }
>  
> -/* Create a breakpoint with SAL as location.  Use ADDR_STRING
> -   as textual description of the location, and COND_STRING
> +/* Create a breakpoint with SAL as location.  Use LOCATION
> +   as a description of the location, and COND_STRING
>     as condition expression.  */
>  
>  static void
>  init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
> -		     struct symtabs_and_lines sals, char *addr_string,
> +		     struct symtabs_and_lines sals,
> +		     struct event_location *location,
>  		     char *filter, char *cond_string,
>  		     char *extra_string,
>  		     enum bptype type, enum bpdisp disposition,
> @@ -9138,7 +9162,10 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
>  	  b->task = task;
>  
>  	  b->cond_string = cond_string;
> -	  b->extra_string = extra_string;
> +	  if (extra_string != NULL && *extra_string != '\0')
> +	    b->extra_string = extra_string;
> +	  else
> +	    b->extra_string = NULL;
>  	  b->ignore_count = ignore_count;
>  	  b->enable_state = enabled ? bp_enabled : bp_disabled;
>  	  b->disposition = disposition;
> @@ -9155,13 +9182,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
>  		{
>  		  /* We already know the marker exists, otherwise, we
>  		     wouldn't see a sal for it.  */
> -		  char *p = &addr_string[3];
> -		  char *endp;
> +		  const char *p = &event_location_to_string (b->location)[3];
> +		  const char *endp;
>  		  char *marker_str;
>  
> -		  p = skip_spaces (p);
> +		  p = skip_spaces_const (p);
>  
> -		  endp = skip_to_space (p);
> +		  endp = skip_to_space_const (p);
>  
>  		  marker_str = savestring (p, endp - p);
>  		  t->static_trace_marker_id = marker_str;
> @@ -9217,19 +9244,26 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
>      }
>  
>    b->display_canonical = display_canonical;
> -  if (addr_string)
> -    b->addr_string = addr_string;
> +  if (location != NULL)
> +    b->location = location;
>    else
> -    /* addr_string has to be used or breakpoint_re_set will delete
> -       me.  */
> -    b->addr_string
> -      = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
> +    {
> +      char *tmp;
> +      struct cleanup *cleanup;
> +
> +      tmp = xstrprintf ("*%s",
> +			    paddress (b->loc->gdbarch, b->loc->address));
> +      cleanup = make_cleanup (xfree, tmp);
> +      b->location = new_linespec_location (&tmp);
> +      do_cleanups (cleanup);
> +   }
>    b->filter = filter;
>  }
>  
>  static void
>  create_breakpoint_sal (struct gdbarch *gdbarch,
> -		       struct symtabs_and_lines sals, char *addr_string,
> +		       struct symtabs_and_lines sals,
> +		       struct event_location *location,
>  		       char *filter, char *cond_string,
>  		       char *extra_string,
>  		       enum bptype type, enum bpdisp disposition,
> @@ -9254,7 +9288,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
>    old_chain = make_cleanup (xfree, b);
>  
>    init_breakpoint_sal (b, gdbarch,
> -		       sals, addr_string,
> +		       sals, location,
>  		       filter, cond_string, extra_string,
>  		       type, disposition,
>  		       thread, task, ignore_count,
> @@ -9298,17 +9332,17 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
>  
>    for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
>      {
> -      /* Note that 'addr_string' can be NULL in the case of a plain
> +      /* Note that 'location' can be NULL in the case of a plain
>  	 'break', without arguments.  */
> -      char *addr_string = (canonical->addr_string
> -			   ? xstrdup (canonical->addr_string)
> -			   : NULL);
> +      struct event_location *location
> +	= (canonical->location != NULL
> +	   ? copy_event_location (canonical->location) : NULL);
>        char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
> -      struct cleanup *inner = make_cleanup (xfree, addr_string);
> +      struct cleanup *inner = make_cleanup_delete_event_location (location);
>  
>        make_cleanup (xfree, filter_string);
>        create_breakpoint_sal (gdbarch, lsal->sals,
> -			     addr_string,
> +			     location,
>  			     filter_string,
>  			     cond_string, extra_string,
>  			     type, disposition,
> @@ -9319,83 +9353,97 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
>      }
>  }
>  
> -/* Parse ADDRESS which is assumed to be a SAL specification possibly
> +/* Parse LOCATION which is assumed to be a SAL specification possibly
>     followed by conditionals.  On return, SALS contains an array of SAL
> -   addresses found.  ADDR_STRING contains a vector of (canonical)
> -   address strings.  ADDRESS points to the end of the SAL.
> +   addresses found.  LOCATION points to the end of the SAL (for
> +   linespec locations).
>  
>     The array and the line spec strings are allocated on the heap, it is
>     the caller's responsibility to free them.  */
>  
>  static void
> -parse_breakpoint_sals (char **address,
> +parse_breakpoint_sals (const struct event_location *location,
>  		       struct linespec_result *canonical)
>  {
> -  /* If no arg given, or if first arg is 'if ', use the default
> -     breakpoint.  */
> -  if ((*address) == NULL || linespec_lexer_lex_keyword (*address))
> -    {
> -      /* The last displayed codepoint, if it's valid, is our default breakpoint
> -         address.  */
> -      if (last_displayed_sal_is_valid ())
> -	{
> -	  struct linespec_sals lsal;
> -	  struct symtab_and_line sal;
> -	  CORE_ADDR pc;
> -
> -	  init_sal (&sal);		/* Initialize to zeroes.  */
> -	  lsal.sals.sals = (struct symtab_and_line *)
> -	    xmalloc (sizeof (struct symtab_and_line));
> -
> -	  /* Set sal's pspace, pc, symtab, and line to the values
> -	     corresponding to the last call to print_frame_info.
> -	     Be sure to reinitialize LINE with NOTCURRENT == 0
> -	     as the breakpoint line number is inappropriate otherwise.
> -	     find_pc_line would adjust PC, re-set it back.  */
> -	  get_last_displayed_sal (&sal);
> -	  pc = sal.pc;
> -	  sal = find_pc_line (pc, 0);
> -
> -	  /* "break" without arguments is equivalent to "break *PC"
> -	     where PC is the last displayed codepoint's address.  So
> -	     make sure to set sal.explicit_pc to prevent GDB from
> -	     trying to expand the list of sals to include all other
> -	     instances with the same symtab and line.  */
> -	  sal.pc = pc;
> -	  sal.explicit_pc = 1;
> -
> -	  lsal.sals.sals[0] = sal;
> -	  lsal.sals.nelts = 1;
> -	  lsal.canonical = NULL;
> -
> -	  VEC_safe_push (linespec_sals, canonical->sals, &lsal);
> +  struct symtab_and_line cursal;
> +
> +  if (event_location_type (location) == LINESPEC_LOCATION)
> +    {
> +      const char *address = get_linespec_location (location);
> +
> +      if (address == NULL)
> +	{
> +	  /* The last displayed codepoint, if it's valid, is our default
> +	     breakpoint address.  */
> +	  if (last_displayed_sal_is_valid ())
> +	    {
> +	      struct linespec_sals lsal;
> +	      struct symtab_and_line sal;
> +	      CORE_ADDR pc;
> +
> +	      init_sal (&sal);		/* Initialize to zeroes.  */
> +	      lsal.sals.sals = (struct symtab_and_line *)
> +		xmalloc (sizeof (struct symtab_and_line));
> +
> +	      /* Set sal's pspace, pc, symtab, and line to the values
> +		 corresponding to the last call to print_frame_info.
> +		 Be sure to reinitialize LINE with NOTCURRENT == 0
> +		 as the breakpoint line number is inappropriate otherwise.
> +		 find_pc_line would adjust PC, re-set it back.  */
> +	      get_last_displayed_sal (&sal);
> +	      pc = sal.pc;
> +	      sal = find_pc_line (pc, 0);
> +
> +	      /* "break" without arguments is equivalent to "break *PC"
> +		 where PC is the last displayed codepoint's address.  So
> +		 make sure to set sal.explicit_pc to prevent GDB from
> +		 trying to expand the list of sals to include all other
> +		 instances with the same symtab and line.  */
> +	      sal.pc = pc;
> +	      sal.explicit_pc = 1;
> +
> +	      lsal.sals.sals[0] = sal;
> +	      lsal.sals.nelts = 1;
> +	      lsal.canonical = NULL;
> +
> +	      VEC_safe_push (linespec_sals, canonical->sals, &lsal);
> +	      return;
> +	    }
> +	  else
> +	    error (_("No default breakpoint address now."));
>  	}
> -      else
> -	error (_("No default breakpoint address now."));
>      }
> -  else
> +
> +  /* Force almost all breakpoints to be in terms of the
> +     current_source_symtab (which is decode_line_1's default).
> +     This should produce the results we want almost all of the
> +     time while leaving default_breakpoint_* alone.
> +
> +     ObjC: However, don't match an Objective-C method name which
> +     may have a '+' or '-' succeeded by a '['.  */
> +  cursal = get_current_source_symtab_and_line ();
> +  if (last_displayed_sal_is_valid ())
>      {
> -      struct symtab_and_line cursal = get_current_source_symtab_and_line ();
> +      const char *address = NULL;
>  
> -      /* Force almost all breakpoints to be in terms of the
> -         current_source_symtab (which is decode_line_1's default).
> -         This should produce the results we want almost all of the
> -         time while leaving default_breakpoint_* alone.
> +      if (event_location_type (location) == LINESPEC_LOCATION)
> +	address = get_linespec_location (location);
>  
> -	 ObjC: However, don't match an Objective-C method name which
> -	 may have a '+' or '-' succeeded by a '['.  */
> -      if (last_displayed_sal_is_valid ()
> -	  && (!cursal.symtab
> -	      || ((strchr ("+-", (*address)[0]) != NULL)
> -		  && ((*address)[1] != '['))))
> -	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
> -			  get_last_displayed_symtab (),
> -			  get_last_displayed_line (),
> -			  canonical, NULL, NULL);
> -      else
> -	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
> -			  cursal.symtab, cursal.line, canonical, NULL, NULL);
> +      if (!cursal.symtab
> +	  || (address != NULL
> +	      && strchr ("+-", address[0]) != NULL
> +	      && address[1] != '['))
> +	{
> +	  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
> +			    get_last_displayed_symtab (),
> +			    get_last_displayed_line (),
> +			    canonical, NULL, NULL);
> +	  return;
> +	}
>      }
> +
> +  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
> +		    cursal.symtab, cursal.line, canonical, NULL, NULL);
>  }
>  
>  
> @@ -9541,19 +9589,19 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
>  /* Decode a static tracepoint marker spec.  */
>  
>  static struct symtabs_and_lines
> -decode_static_tracepoint_spec (char **arg_p)
> +decode_static_tracepoint_spec (const char **arg_p)
>  {
>    VEC(static_tracepoint_marker_p) *markers = NULL;
>    struct symtabs_and_lines sals;
>    struct cleanup *old_chain;
> -  char *p = &(*arg_p)[3];
> -  char *endp;
> +  const char *p = &(*arg_p)[3];
> +  const char *endp;
>    char *marker_str;
>    int i;
>  
> -  p = skip_spaces (p);
> +  p = skip_spaces_const (p);
>  
> -  endp = skip_to_space (p);
> +  endp = skip_to_space_const (p);
>  
>    marker_str = savestring (p, endp - p);
>    old_chain = make_cleanup (xfree, marker_str);
> @@ -9585,22 +9633,13 @@ decode_static_tracepoint_spec (char **arg_p)
>    return sals;
>  }
>  
> -/* Set a breakpoint.  This function is shared between CLI and MI
> -   functions for setting a breakpoint.  This function has two major
> -   modes of operations, selected by the PARSE_ARG parameter.  If
> -   non-zero, the function will parse ARG, extracting location,
> -   condition, thread and extra string.  Otherwise, ARG is just the
> -   breakpoint's location, with condition, thread, and extra string
> -   specified by the COND_STRING, THREAD and EXTRA_STRING parameters.
> -   If INTERNAL is non-zero, the breakpoint number will be allocated
> -   from the internal breakpoint count.  Returns true if any breakpoint
> -   was created; false otherwise.  */
> +/* See breakpoint.h.  */
>  
>  int
>  create_breakpoint (struct gdbarch *gdbarch,
> -		   char *arg, char *cond_string,
> +		   const struct event_location *location, char *cond_string,
>  		   int thread, char *extra_string,
> -		   int parse_arg,
> +		   int parse_extra,
>  		   int tempflag, enum bptype type_wanted,
>  		   int ignore_count,
>  		   enum auto_boolean pending_break_support,
> @@ -9608,8 +9647,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>  		   int from_tty, int enabled, int internal,
>  		   unsigned flags)
>  {
> -  char *copy_arg = NULL;
> -  char *addr_start = arg;
>    struct linespec_result canonical;
>    struct cleanup *old_chain;
>    struct cleanup *bkpt_chain = NULL;
> @@ -9619,12 +9656,15 @@ create_breakpoint (struct gdbarch *gdbarch,
>  
>    gdb_assert (ops != NULL);
>  
> +  /* If extra_string isn't useful, set it to NULL.  */
> +  if (extra_string != NULL && *extra_string == '\0')
> +    extra_string = NULL;
> +
>    init_linespec_result (&canonical);
>  
>    TRY
>      {
> -      ops->create_sals_from_location (&arg, &canonical, type_wanted,
> -				      addr_start, &copy_arg);
> +      ops->create_sals_from_location (location, &canonical, type_wanted);
>      }
>    CATCH (e, RETURN_MASK_ERROR)
>      {
> @@ -9651,24 +9691,14 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	     a pending breakpoint and selected yes, or pending
>  	     breakpoint behavior is on and thus a pending breakpoint
>  	     is defaulted on behalf of the user.  */
> -	  {
> -	    struct linespec_sals lsal;
> -
> -	    copy_arg = xstrdup (addr_start);
> -	    lsal.canonical = xstrdup (copy_arg);
> -	    lsal.sals.nelts = 1;
> -	    lsal.sals.sals = XNEW (struct symtab_and_line);
> -	    init_sal (&lsal.sals.sals[0]);
> -	    pending = 1;
> -	    VEC_safe_push (linespec_sals, canonical.sals, &lsal);
> -	  }
> +	  pending = 1;
>  	}
>        else
>  	throw_exception (e);
>      }
>    END_CATCH
>  
> -  if (VEC_empty (linespec_sals, canonical.sals))
> +  if (!pending && VEC_empty (linespec_sals, canonical.sals))
>      return 0;
>  
>    /* Create a chain of things that always need to be cleaned up.  */
> @@ -9706,7 +9736,7 @@ create_breakpoint (struct gdbarch *gdbarch,
>       breakpoint.  */
>    if (!pending)
>      {
> -      if (parse_arg)
> +      if (parse_extra)
>          {
>  	  char *rest;
>  	  struct linespec_sals *lsal;
> @@ -9718,19 +9748,22 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	     sal is OK.  When setting the breakpoint we'll
>  	     re-parse it in context of each sal.  */
>  
> -	  find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
> -				     &thread, &task, &rest);
> +	  find_condition_and_thread (extra_string, lsal->sals.sals[0].pc,
> +				     &cond_string, &thread, &task, &rest);
>  	  if (cond_string)
>  	    make_cleanup (xfree, cond_string);
>  	  if (rest)
>  	    make_cleanup (xfree, rest);
>  	  if (rest)
>  	    extra_string = rest;
> +	  else
> +	    extra_string = NULL;
>          }
>        else
>          {
> -	  if (*arg != '\0')
> -	    error (_("Garbage '%s' at end of location"), arg);
> +	  if (type_wanted != bp_dprintf
> +	      && extra_string != NULL && *extra_string != '\0')
> +		error (_("Garbage '%s' at end of location"), extra_string);
>  
>  	  /* Create a private copy of condition string.  */
>  	  if (cond_string)
> @@ -9756,8 +9789,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>      {
>        struct breakpoint *b;
>  
> -      make_cleanup (xfree, copy_arg);
> -
>        if (is_tracepoint_type (type_wanted))
>  	{
>  	  struct tracepoint *t;
> @@ -9769,9 +9800,22 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	b = XNEW (struct breakpoint);
>  
>        init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
> +      b->location = copy_event_location (location);
> +
> +      /* Append extra_string, if set, to the canonical representation
> +	 of the lsal.  This preserves any conditions that the user may
> +	 have specified.  */
> +      if (extra_string != NULL)
> +	{
> +	  char *new = xstrprintf ("%s %s",
> +				  event_location_to_string_const (location),
> +				  extra_string);
>  
> -      b->addr_string = copy_arg;
> -      if (parse_arg)
> +	  set_event_location_string (b->location, new);
> +	  xfree (new);
> +	}
> +
> +      if (parse_extra)
>  	b->cond_string = NULL;
>        else
>  	{
> @@ -9784,7 +9828,14 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	  b->cond_string = cond_string;
>  	  b->thread = thread;
>  	}
> -      b->extra_string = NULL;
> +
> +      /* Make a private copy of extra_string for the breakpoint.  */
> +      if (extra_string != NULL)
> +	{
> +	  extra_string = xstrdup (extra_string);
> +	  make_cleanup (xfree, extra_string);
> +	}
> +      b->extra_string =  extra_string;
>        b->ignore_count = ignore_count;
>        b->disposition = tempflag ? disp_del : disp_donttouch;
>        b->condition_not_parsed = 1;
> @@ -9831,16 +9882,21 @@ break_command_1 (char *arg, int flag, int from_tty)
>  			     : bp_breakpoint);
>    struct breakpoint_ops *ops;
>    const char *arg_cp = arg;
> +  struct event_location *location;
> +  struct cleanup *cleanup;
> +
> +  location = string_to_event_location (&arg, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
>  
>    /* Matching breakpoints on probes.  */
> -  if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
> +  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
>      ops = &bkpt_probe_breakpoint_ops;
>    else
>      ops = &bkpt_breakpoint_ops;
>  
>    create_breakpoint (get_current_arch (),
> -		     arg,
> -		     NULL, 0, NULL, 1 /* parse arg */,
> +		     location,
> +		     NULL, 0, arg, 1 /* parse arg */,
>  		     tempflag, type_wanted,
>  		     0 /* Ignore count */,
>  		     pending_break_support,
> @@ -9849,6 +9905,7 @@ break_command_1 (char *arg, int flag, int from_tty)
>  		     1 /* enabled */,
>  		     0 /* internal */,
>  		     0);
> +  do_cleanups (cleanup);
>  }
>  
>  /* Helper function for break_command_1 and disassemble_command.  */
> @@ -10015,9 +10072,15 @@ stopat_command (char *arg, int from_tty)
>  static void
>  dprintf_command (char *arg, int from_tty)
>  {
> +  struct event_location *location;
> +  struct cleanup *cleanup;
> +
> +  location = string_to_event_location (&arg, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
> +
>    create_breakpoint (get_current_arch (),
> -		     arg,
> -		     NULL, 0, NULL, 1 /* parse arg */,
> +		     location,
> +		     NULL, 0, arg, 1 /* parse arg */,
>  		     0, bp_dprintf,
>  		     0 /* Ignore count */,
>  		     pending_break_support,
> @@ -10026,6 +10089,7 @@ dprintf_command (char *arg, int from_tty)
>  		     1 /* enabled */,
>  		     0 /* internal */,
>  		     0);
> +  do_cleanups (cleanup);
>  }
>  
>  static void
> @@ -10170,8 +10234,9 @@ print_mention_ranged_breakpoint (struct breakpoint *b)
>  static void
>  print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
>  {
> -  fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
> -		      b->addr_string_range_end);
> +  fprintf_unfiltered (fp, "break-range %s, %s",
> +		      event_location_to_string (b->location),
> +		      event_location_to_string (b->location_range_end));
>    print_recreate_thread (b, fp);
>  }
>  
> @@ -10222,6 +10287,7 @@ break_range_command (char *arg, int from_tty)
>    struct symtab_and_line sal_start, sal_end;
>    struct cleanup *cleanup_bkpt;
>    struct linespec_sals *lsal_start, *lsal_end;
> +  struct event_location *start_location, *end_location;
>  
>    /* We don't support software ranged breakpoints.  */
>    if (target_ranged_break_num_registers () < 0)
> @@ -10241,9 +10307,10 @@ break_range_command (char *arg, int from_tty)
>    init_linespec_result (&canonical_start);
>  
>    arg_start = arg;
> -  parse_breakpoint_sals (&arg, &canonical_start);
> -
> -  cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
> +  start_location = string_to_event_location (&arg, current_language);
> +  cleanup_bkpt = make_cleanup_delete_event_location (start_location);
> +  parse_breakpoint_sals (start_location, &canonical_start);
> +  make_cleanup_destroy_linespec_result (&canonical_start);
>  
>    if (arg[0] != ',')
>      error (_("Too few arguments."));
> @@ -10273,7 +10340,9 @@ break_range_command (char *arg, int from_tty)
>       symtab and line as the default symtab and line for the end of the
>       range.  This makes it possible to have ranges like "foo.c:27, +14",
>       where +14 means 14 lines from the start location.  */
> -  decode_line_full (&arg, DECODE_LINE_FUNFIRSTLINE,
> +  end_location = string_to_event_location (&arg, current_language);
> +  make_cleanup_delete_event_location (end_location);
> +  decode_line_full (end_location, DECODE_LINE_FUNFIRSTLINE,
>  		    sal_start.symtab, sal_start.line,
>  		    &canonical_end, NULL, NULL);
>  
> @@ -10288,8 +10357,6 @@ break_range_command (char *arg, int from_tty)
>      error (_("Cannot create a ranged breakpoint with multiple locations."));
>  
>    sal_end = lsal_end->sals.sals[0];
> -  addr_string_end = savestring (arg_start, arg - arg_start);
> -  make_cleanup (xfree, addr_string_end);
>  
>    end = find_breakpoint_range_end (sal_end);
>    if (sal_start.pc > end)
> @@ -10316,8 +10383,8 @@ break_range_command (char *arg, int from_tty)
>    set_breakpoint_count (breakpoint_count + 1);
>    b->number = breakpoint_count;
>    b->disposition = disp_donttouch;
> -  b->addr_string = xstrdup (addr_string_start);
> -  b->addr_string_range_end = xstrdup (addr_string_end);
> +  b->location = copy_event_location (start_location);
> +  b->location_range_end = copy_event_location (end_location);
>    b->loc->length = length;
>  
>    do_cleanups (cleanup_bkpt);
> @@ -11444,21 +11511,25 @@ until_break_command (char *arg, int from_tty, int anywhere)
>    struct frame_id caller_frame_id;
>    struct breakpoint *breakpoint;
>    struct breakpoint *breakpoint2 = NULL;
> -  struct cleanup *old_chain;
> +  struct cleanup *old_chain, *cleanup;
>    int thread;
>    struct thread_info *tp;
> +  struct event_location *location;
>  
>    clear_proceed_status (0);
>  
>    /* Set a breakpoint where the user wants it and at return from
>       this function.  */
>  
> +  location = string_to_event_location (&arg, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
> +
>    if (last_displayed_sal_is_valid ())
> -    sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE,
> +    sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
>  			  get_last_displayed_symtab (),
>  			  get_last_displayed_line ());
>    else
> -    sals = decode_line_1 (&arg, DECODE_LINE_FUNFIRSTLINE,
> +    sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE,
>  			  (struct symtab *) NULL, 0);
>  
>    if (sals.nelts != 1)
> @@ -11544,6 +11615,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
>      }
>    else
>      do_cleanups (old_chain);
> +
> +  do_cleanups (cleanup);
>  }
>  
>  /* This function attempts to parse an optional "if <cond>" clause
> @@ -11699,7 +11772,8 @@ init_ada_exception_breakpoint (struct breakpoint *b,
>  
>    b->enable_state = enabled ? bp_enabled : bp_disabled;
>    b->disposition = tempflag ? disp_del : disp_donttouch;
> -  b->addr_string = addr_string;
> +  b->location = string_to_event_location (&addr_string,
> +					  language_def (language_ada));
>    b->language = language_ada;
>  }
>  
> @@ -12569,7 +12643,8 @@ say_where (struct breakpoint *b)
>       single string.  */
>    if (b->loc == NULL)
>      {
> -      printf_filtered (_(" (%s) pending."), b->addr_string);
> +      printf_filtered (_(" (%s) pending."),
> +		       event_location_to_string (b->location));
>      }
>    else
>      {
> @@ -12591,7 +12666,8 @@ say_where (struct breakpoint *b)
>  	    /* This is not ideal, but each location may have a
>  	       different file name, and this at least reflects the
>  	       real situation somewhat.  */
> -	    printf_filtered (": %s.", b->addr_string);
> +	    printf_filtered (": %s.",
> +			     event_location_to_string (b->location));
>  	}
>  
>        if (b->loc->next)
> @@ -12633,9 +12709,9 @@ base_breakpoint_dtor (struct breakpoint *self)
>    decref_counted_command_line (&self->commands);
>    xfree (self->cond_string);
>    xfree (self->extra_string);
> -  xfree (self->addr_string);
>    xfree (self->filter);
> -  xfree (self->addr_string_range_end);
> +  delete_event_location (self->location);
> +  delete_event_location (self->location_range_end);
>  }
>  
>  static struct bp_location *
> @@ -12728,11 +12804,10 @@ base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
>  }
>  
>  static void
> -base_breakpoint_create_sals_from_location (char **arg,
> -					   struct linespec_result *canonical,
> -					   enum bptype type_wanted,
> -					   char *addr_start,
> -					   char **copy_arg)
> +base_breakpoint_create_sals_from_location
> +  (const struct event_location *location,
> +   struct linespec_result *canonical,
> +   enum bptype type_wanted)
>  {
>    internal_error_pure_virtual_called ();
>  }
> @@ -12754,7 +12829,8 @@ base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch,
>  }
>  
>  static void
> -base_breakpoint_decode_location (struct breakpoint *b, char **s,
> +base_breakpoint_decode_location (struct breakpoint *b,
> +				 const struct event_location *location,
>  				 struct symtabs_and_lines *sals)
>  {
>    internal_error_pure_virtual_called ();
> @@ -12805,9 +12881,9 @@ static void
>  bkpt_re_set (struct breakpoint *b)
>  {
>    /* FIXME: is this still reachable?  */
> -  if (b->addr_string == NULL)
> +  if (event_location_empty_p (b->location))
>      {
> -      /* Anything without a string can't be re-set.  */
> +      /* Anything without a location can't be re-set.  */
>        delete_breakpoint (b);
>        return;
>      }
> @@ -12959,18 +13035,17 @@ bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
>      internal_error (__FILE__, __LINE__,
>  		    _("unhandled breakpoint type %d"), (int) tp->type);
>  
> -  fprintf_unfiltered (fp, " %s", tp->addr_string);
> +  fprintf_unfiltered (fp, " %s",
> +		      event_location_to_string (tp->location));
>    print_recreate_thread (tp, fp);
>  }
>  
>  static void
> -bkpt_create_sals_from_location (char **arg,
> -			       struct linespec_result *canonical,
> -			       enum bptype type_wanted,
> -			       char *addr_start, char **copy_arg)
> +bkpt_create_sals_from_location (const struct event_location *location,
> +				struct linespec_result *canonical,
> +				enum bptype type_wanted)
>  {
> -  create_sals_from_location_default (arg, canonical, type_wanted,
> -				    addr_start, copy_arg);
> +  create_sals_from_location_default (location, canonical, type_wanted);
>  }
>  
>  static void
> @@ -12995,10 +13070,11 @@ bkpt_create_breakpoints_sal (struct gdbarch *gdbarch,
>  }
>  
>  static void
> -bkpt_decode_location (struct breakpoint *b, char **s,
> +bkpt_decode_location (struct breakpoint *b,
> +		      const struct event_location *location,
>  		      struct symtabs_and_lines *sals)
>  {
> -  decode_location_default (b, s, sals);
> +  decode_location_default (b, location, sals);
>  }
>  
>  /* Virtual table for internal breakpoints.  */
> @@ -13198,26 +13274,23 @@ bkpt_probe_remove_location (struct bp_location *bl)
>  }
>  
>  static void
> -bkpt_probe_create_sals_from_location (char **arg,
> +bkpt_probe_create_sals_from_location (const struct event_location *location,
>  				      struct linespec_result *canonical,
> -				      enum bptype type_wanted,
> -				      char *addr_start, char **copy_arg)
> +				      enum bptype type_wanted)
>  {
>    struct linespec_sals lsal;
>  
> -  lsal.sals = parse_probes (arg, canonical);
> -
> -  *copy_arg = xstrdup (canonical->addr_string);
> -  lsal.canonical = xstrdup (*copy_arg);
> -
> +  lsal.sals = parse_probes (location, canonical);
> +  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
>    VEC_safe_push (linespec_sals, canonical->sals, &lsal);
>  }
>  
>  static void
> -bkpt_probe_decode_location (struct breakpoint *b, char **s,
> +bkpt_probe_decode_location (struct breakpoint *b,
> +			    const struct event_location *location,
>  			    struct symtabs_and_lines *sals)
>  {
> -  *sals = parse_probes (s, NULL);
> +  *sals = parse_probes (location, NULL);
>    if (!sals->sals)
>      error (_("probe not found"));
>  }
> @@ -13299,7 +13372,8 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
>      internal_error (__FILE__, __LINE__,
>  		    _("unhandled tracepoint type %d"), (int) self->type);
>  
> -  fprintf_unfiltered (fp, " %s", self->addr_string);
> +  fprintf_unfiltered (fp, " %s",
> +		      event_location_to_string (self->location));
>    print_recreate_thread (self, fp);
>  
>    if (tp->pass_count)
> @@ -13307,13 +13381,11 @@ tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
>  }
>  
>  static void
> -tracepoint_create_sals_from_location (char **arg,
> -				     struct linespec_result *canonical,
> -				     enum bptype type_wanted,
> -				     char *addr_start, char **copy_arg)
> +tracepoint_create_sals_from_location (const struct event_location *location,
> +				      struct linespec_result *canonical,
> +				      enum bptype type_wanted)
>  {
> -  create_sals_from_location_default (arg, canonical, type_wanted,
> -				    addr_start, copy_arg);
> +  create_sals_from_location_default (location, canonical, type_wanted);
>  }
>  
>  static void
> @@ -13338,10 +13410,11 @@ tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch,
>  }
>  
>  static void
> -tracepoint_decode_location (struct breakpoint *b, char **s,
> +tracepoint_decode_location (struct breakpoint *b,
> +			    const struct event_location *location,
>  			    struct symtabs_and_lines *sals)
>  {
> -  decode_location_default (b, s, sals);
> +  decode_location_default (b, location, sals);
>  }
>  
>  struct breakpoint_ops tracepoint_breakpoint_ops;
> @@ -13350,22 +13423,22 @@ struct breakpoint_ops tracepoint_breakpoint_ops;
>     static probe.  */
>  
>  static void
> -tracepoint_probe_create_sals_from_location (char **arg,
> -					    struct linespec_result *canonical,
> -					    enum bptype type_wanted,
> -					    char *addr_start, char **copy_arg)
> +tracepoint_probe_create_sals_from_location
> +  (const struct event_location *location,
> +   struct linespec_result *canonical,
> +   enum bptype type_wanted)
>  {
>    /* We use the same method for breakpoint on probes.  */
> -  bkpt_probe_create_sals_from_location (arg, canonical, type_wanted,
> -					addr_start, copy_arg);
> +  bkpt_probe_create_sals_from_location (location, canonical, type_wanted);
>  }
>  
>  static void
> -tracepoint_probe_decode_location (struct breakpoint *b, char **s,
> +tracepoint_probe_decode_location (struct breakpoint *b,
> +				  const struct event_location *location,
>  				  struct symtabs_and_lines *sals)
>  {
>    /* We use the same method for breakpoint on probes.  */
> -  bkpt_probe_decode_location (b, s, sals);
> +  bkpt_probe_decode_location (b, location, sals);
>  }
>  
>  static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
> @@ -13404,7 +13477,8 @@ dprintf_re_set (struct breakpoint *b)
>  static void
>  dprintf_print_recreate (struct breakpoint *tp, struct ui_file *fp)
>  {
> -  fprintf_unfiltered (fp, "dprintf %s%s", tp->addr_string,
> +  fprintf_unfiltered (fp, "dprintf %s%s",
> +		      event_location_to_string (tp->location),
>  		      tp->extra_string);
>    print_recreate_thread (tp, fp);
>  }
> @@ -13451,19 +13525,28 @@ dprintf_after_condition_true (struct bpstats *bs)
>     markers (`-m').  */
>  
>  static void
> -strace_marker_create_sals_from_location (char **arg,
> +strace_marker_create_sals_from_location (const struct event_location *location,
>  					 struct linespec_result *canonical,
> -					 enum bptype type_wanted,
> -					 char *addr_start, char **copy_arg)
> +					 enum bptype type_wanted)
>  {
>    struct linespec_sals lsal;
> +  const char *arg_start, *arg;
>  
> -  lsal.sals = decode_static_tracepoint_spec (arg);
> +  arg = arg_start = get_linespec_location (location);
> +  lsal.sals = decode_static_tracepoint_spec (&arg);
>  
> -  *copy_arg = savestring (addr_start, *arg - addr_start);
> +  if (canonical != NULL)

Why the canonical != NULL test here?
Outside this "if" below it's assumed canonical != NULL.

> +    {
> +      char *str;
> +      struct cleanup *cleanup;
>  
> -  canonical->addr_string = xstrdup (*copy_arg);
> -  lsal.canonical = xstrdup (*copy_arg);
> +      str = savestring (arg_start, arg - arg_start);
> +      cleanup = make_cleanup (xfree, str);
> +      canonical->location = new_linespec_location (&str);
> +      do_cleanups (cleanup);
> +    }
> +
> +  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
>    VEC_safe_push (linespec_sals, canonical->sals, &lsal);
>  }
>  
> @@ -13496,17 +13579,17 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
>        struct symtabs_and_lines expanded;
>        struct tracepoint *tp;
>        struct cleanup *old_chain;
> -      char *addr_string;
> +      struct event_location *location;
>  
>        expanded.nelts = 1;
>        expanded.sals = &lsal->sals.sals[i];
>  
> -      addr_string = xstrdup (canonical->addr_string);
> -      old_chain = make_cleanup (xfree, addr_string);
> +      location = copy_event_location (canonical->location);
> +      old_chain = make_cleanup_delete_event_location (location);
>  
>        tp = XCNEW (struct tracepoint);
>        init_breakpoint_sal (&tp->base, gdbarch, expanded,
> -			   addr_string, NULL,
> +			   location, NULL,
>  			   cond_string, extra_string,
>  			   type_wanted, disposition,
>  			   thread, task, ignore_count, ops,
> @@ -13527,12 +13610,14 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
>  }
>  
>  static void
> -strace_marker_decode_location (struct breakpoint *b, char **s,
> +strace_marker_decode_location (struct breakpoint *b,
> +			       const struct event_location *location,
>  			       struct symtabs_and_lines *sals)
>  {
>    struct tracepoint *tp = (struct tracepoint *) b;
> +  const char *s = get_linespec_location (location);
>  
> -  *sals = decode_static_tracepoint_spec (s);
> +  *sals = decode_static_tracepoint_spec (&s);
>    if (sals->nelts > tp->static_trace_marker_id_idx)
>      {
>        sals->sals[0] = sals->sals[tp->static_trace_marker_id_idx];
> @@ -13864,10 +13949,12 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
>  
>        if (!VEC_empty(static_tracepoint_marker_p, markers))
>  	{
> +	  char *p, *tmp;
>  	  struct symtab_and_line sal2;
>  	  struct symbol *sym;
>  	  struct static_tracepoint_marker *tpmarker;
>  	  struct ui_out *uiout = current_uiout;
> +	  struct cleanup *cleanup;
>  
>  	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
>  
> @@ -13908,10 +13995,13 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
>  	  b->loc->line_number = sal2.line;
>  	  b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
>  
> -	  xfree (b->addr_string);
> -	  b->addr_string = xstrprintf ("%s:%d",
> -				   symtab_to_filename_for_display (sal2.symtab),
> -				       b->loc->line_number);
> +	  delete_event_location (b->location);
> +	  p = tmp = xstrprintf ("%s:%d",
> +				symtab_to_filename_for_display (sal2.symtab),
> +				b->loc->line_number);
> +	  cleanup = make_cleanup (xfree, tmp);
> +	  b->location = new_linespec_location (&tmp);
> +	  do_cleanups (cleanup);
>  
>  	  /* Might be nice to check if function changed, and warn if
>  	     so.  */
> @@ -14068,22 +14158,21 @@ update_breakpoint_locations (struct breakpoint *b,
>    update_global_location_list (UGLL_MAY_INSERT);
>  }
>  
> -/* Find the SaL locations corresponding to the given ADDR_STRING.
> +/* Find the SaL locations corresponding to the given LOCATION.
>     On return, FOUND will be 1 if any SaL was found, zero otherwise.  */
>  
>  static struct symtabs_and_lines
> -location_to_sals (struct breakpoint *b, char *addr_string, int *found)
> +location_to_sals (struct breakpoint *b, struct event_location *location,
> +		  int *found)
>  {
> -  char *s;
>    struct symtabs_and_lines sals = {0};
>    struct gdb_exception exception = exception_none;
>  
>    gdb_assert (b->ops != NULL);
> -  s = addr_string;
>  
>    TRY
>      {
> -      b->ops->decode_location (b, &s, &sals);
> +      b->ops->decode_location (b, location, &sals);
>      }
>    CATCH (e, RETURN_MASK_ERROR)
>      {
> @@ -14125,12 +14214,13 @@ location_to_sals (struct breakpoint *b, char *addr_string, int *found)
>  
>        for (i = 0; i < sals.nelts; ++i)
>  	resolve_sal_pc (&sals.sals[i]);
> -      if (b->condition_not_parsed && s && s[0])
> +      if (b->condition_not_parsed && b->extra_string != NULL)
>  	{
>  	  char *cond_string, *extra_string;
>  	  int thread, task;
> +	  const char *orig = b->extra_string;
>  
> -	  find_condition_and_thread (s, sals.sals[0].pc,
> +	  find_condition_and_thread (b->extra_string, sals.sals[0].pc,
>  				     &cond_string, &thread, &task,
>  				     &extra_string);
>  	  if (cond_string)

The code is a bit odd here, at first glance.
We xfree b->extra_string before assigning a new value,
but not b->cond_string.
I'm guessing this is because the latter will always be NULL here.
Can you add an assert to that effect?  I.e.,

  gdb_assert (b->cond_string == NULL);

> @@ -14138,8 +14228,18 @@ location_to_sals (struct breakpoint *b, char *addr_string, int *found)
>  	  b->thread = thread;
>  	  b->task = task;
>  	  if (extra_string)
> -	    b->extra_string = extra_string;
> +	    {
> +	      xfree (b->extra_string);
> +	      b->extra_string = extra_string;
> +	    }
>  	  b->condition_not_parsed = 0;
> +
> +	  /* If the breakpoint was pending and is now resolved,
> +	     clear the location's string representation.  This
> +	     is necessary since pending breakpoints may have
> +	     condition, thread, or task keywords embedded into it.  */
> +	  if (b->loc == NULL)
> +	    set_event_location_string (b->location, NULL);
>  	}
>  
>        if (b->type == bp_static_tracepoint && !strace_marker_p (b))
> @@ -14165,16 +14265,16 @@ breakpoint_re_set_default (struct breakpoint *b)
>    struct symtabs_and_lines expanded = {0};
>    struct symtabs_and_lines expanded_end = {0};
>  
> -  sals = location_to_sals (b, b->addr_string, &found);
> +  sals = location_to_sals (b, b->location, &found);
>    if (found)
>      {
>        make_cleanup (xfree, sals.sals);
>        expanded = sals;
>      }
>  
> -  if (b->addr_string_range_end)
> +  if (b->location_range_end != NULL)
>      {
> -      sals_end = location_to_sals (b, b->addr_string_range_end, &found);
> +      sals_end = location_to_sals (b, b->location_range_end, &found);
>        if (found)
>  	{
>  	  make_cleanup (xfree, sals_end.sals);
> @@ -14189,12 +14289,11 @@ breakpoint_re_set_default (struct breakpoint *b)
>     calls parse_breakpoint_sals.  Return 1 for success, zero for failure.  */
>  
>  static void
> -create_sals_from_location_default (char **arg,
> -				  struct linespec_result *canonical,
> -				  enum bptype type_wanted,
> -				  char *addr_start, char **copy_arg)
> +create_sals_from_location_default (const struct event_location *location,
> +				   struct linespec_result *canonical,
> +				   enum bptype type_wanted)
>  {
> -  parse_breakpoint_sals (arg, canonical);
> +  parse_breakpoint_sals (location, canonical);
>  }
>  
>  /* Call create_breakpoints_sal for the given arguments.  This is the default
> @@ -14225,13 +14324,14 @@ create_breakpoints_sal_default (struct gdbarch *gdbarch,
>     default function for the `decode_location' method of breakpoint_ops.  */
>  
>  static void
> -decode_location_default (struct breakpoint *b, char **s,
> +decode_location_default (struct breakpoint *b,
> +			 const struct event_location *location,
>  			 struct symtabs_and_lines *sals)
>  {
>    struct linespec_result canonical;
>  
>    init_linespec_result (&canonical);
> -  decode_line_full (s, DECODE_LINE_FUNFIRSTLINE,
> +  decode_line_full (location, DECODE_LINE_FUNFIRSTLINE,
>  		    (struct symtab *) NULL, 0,
>  		    &canonical, multiple_symbols_all,
>  		    b->filter);
> @@ -14903,16 +15003,20 @@ static void
>  trace_command (char *arg, int from_tty)
>  {
>    struct breakpoint_ops *ops;
> +  struct event_location *location;
> +  struct cleanup *back_to;
>    const char *arg_cp = arg;
>  
> -  if (arg && probe_linespec_to_ops (&arg_cp))
> +  location = string_to_event_location (&arg, current_language);
> +  back_to = make_cleanup_delete_event_location (location);
> +  if (arg_cp != NULL && probe_linespec_to_ops (&arg_cp) != NULL)
>      ops = &tracepoint_probe_breakpoint_ops;
>    else
>      ops = &tracepoint_breakpoint_ops;
>  
>    create_breakpoint (get_current_arch (),
> -		     arg,
> -		     NULL, 0, NULL, 1 /* parse arg */,
> +		     location,
> +		     NULL, 0, arg, 1 /* parse arg */,
>  		     0 /* tempflag */,
>  		     bp_tracepoint /* type_wanted */,
>  		     0 /* Ignore count */,
> @@ -14921,14 +15025,20 @@ trace_command (char *arg, int from_tty)
>  		     from_tty,
>  		     1 /* enabled */,
>  		     0 /* internal */, 0);
> +  do_cleanups (back_to);
>  }
>  
>  static void
>  ftrace_command (char *arg, int from_tty)
>  {
> +  struct event_location *location;
> +  struct cleanup *back_to;
> +
> +  location = string_to_event_location (&arg, current_language);
> +  back_to = make_cleanup_delete_event_location (location);
>    create_breakpoint (get_current_arch (),
> -		     arg,
> -		     NULL, 0, NULL, 1 /* parse arg */,
> +		     location,
> +		     NULL, 0, arg, 1 /* parse arg */,
>  		     0 /* tempflag */,
>  		     bp_fast_tracepoint /* type_wanted */,
>  		     0 /* Ignore count */,
> @@ -14937,6 +15047,7 @@ ftrace_command (char *arg, int from_tty)
>  		     from_tty,
>  		     1 /* enabled */,
>  		     0 /* internal */, 0);
> +  do_cleanups (back_to);
>  }
>  
>  /* strace command implementation.  Creates a static tracepoint.  */
> @@ -14945,17 +15056,26 @@ static void
>  strace_command (char *arg, int from_tty)
>  {
>    struct breakpoint_ops *ops;
> +  struct event_location *location;
> +  struct cleanup *back_to;
>  
>    /* Decide if we are dealing with a static tracepoint marker (`-m'),
>       or with a normal static tracepoint.  */
>    if (arg && startswith (arg, "-m") && isspace (arg[2]))
> -    ops = &strace_marker_breakpoint_ops;
> +    {
> +      ops = &strace_marker_breakpoint_ops;
> +      location = new_linespec_location (&arg);
> +    }
>    else
> -    ops = &tracepoint_breakpoint_ops;
> +    {
> +      ops = &tracepoint_breakpoint_ops;
> +      location = string_to_event_location (&arg, current_language);
> +    }
>  
> +  back_to = make_cleanup_delete_event_location (location);
>    create_breakpoint (get_current_arch (),
> -		     arg,
> -		     NULL, 0, NULL, 1 /* parse arg */,
> +		     location,
> +		     NULL, 0, arg, 1 /* parse arg */,
>  		     0 /* tempflag */,
>  		     bp_static_tracepoint /* type_wanted */,
>  		     0 /* Ignore count */,
> @@ -14964,6 +15084,7 @@ strace_command (char *arg, int from_tty)
>  		     from_tty,
>  		     1 /* enabled */,
>  		     0 /* internal */, 0);
> +  do_cleanups (back_to);
>  }
>  
>  /* Set up a fake reader function that gets command lines from a linked
> @@ -14995,6 +15116,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
>  {
>    char *addr_str, small_buf[100];
>    struct tracepoint *tp;
> +  struct event_location *location;
> +  struct cleanup *cleanup;
>  
>    if (utp->at_string)
>      addr_str = utp->at_string;
> @@ -15017,9 +15140,11 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
>  	       "has no source form, ignoring it"),
>  	     utp->number);
>  
> +  location = string_to_event_location (&addr_str, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
>    if (!create_breakpoint (get_current_arch (),
> -			  addr_str,
> -			  utp->cond_string, -1, NULL,
> +			  location,
> +			  utp->cond_string, -1, addr_str,
>  			  0 /* parse cond/thread */,
>  			  0 /* tempflag */,
>  			  utp->type /* type_wanted */,
> @@ -15030,7 +15155,12 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
>  			  utp->enabled /* enabled */,
>  			  0 /* internal */,
>  			  CREATE_BREAKPOINT_FLAGS_INSERTED))
> -    return NULL;
> +    {
> +      do_cleanups (cleanup);
> +      return NULL;
> +    }
> +
> +  do_cleanups (cleanup);
>  
>    /* Get the tracepoint we just created.  */
>    tp = get_tracepoint (tracepoint_count);
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 6f144bd..8921bf0 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -37,6 +37,7 @@ struct bpstats;
>  struct bp_location;
>  struct linespec_result;
>  struct linespec_sals;
> +struct event_location;
>  
>  /* This is the maximum number of bytes a breakpoint instruction can
>     take.  Feel free to increase it.  It's just used in a few places to
> @@ -580,8 +581,9 @@ struct breakpoint_ops
>       `create_sals_from_location_default'.
>  
>       This function is called inside `create_breakpoint'.  */
> -  void (*create_sals_from_location) (char **, struct linespec_result *,
> -				     enum bptype, char *, char **);
> +  void (*create_sals_from_location) (const struct event_location *location,
> +				     struct linespec_result *canonical,
> +				     enum bptype type_wanted);
>  
>    /* This method will be responsible for creating a breakpoint given its SALs.
>       Usually, it just calls `create_breakpoints_sal' (for ordinary
> @@ -602,8 +604,9 @@ struct breakpoint_ops
>       it calls `decode_line_full'.
>  
>       This function is called inside `location_to_sals'.  */
> -  void (*decode_location) (struct breakpoint *, char **,
> -			   struct symtabs_and_lines *);
> +  void (*decode_location) (struct breakpoint *b,
> +			   const struct event_location *location,
> +			   struct symtabs_and_lines *sals);
>  
>    /* Return true if this breakpoint explains a signal.  See
>       bpstat_explains_signal.  */
> @@ -702,17 +705,17 @@ struct breakpoint
>         non-thread-specific ordinary breakpoints this is NULL.  */
>      struct program_space *pspace;
>  
> -    /* String we used to set the breakpoint (malloc'd).  */
> -    char *addr_string;
> +    /* Location we used to set the breakpoint (malloc'd).  */
> +    struct event_location *location;
>  
>      /* The filter that should be passed to decode_line_full when
>         re-setting this breakpoint.  This may be NULL, but otherwise is
>         allocated with xmalloc.  */
>      char *filter;
>  
> -    /* For a ranged breakpoint, the string we used to find
> +    /* For a ranged breakpoint, the location we used to find
>         the end of the range (malloc'd).  */
> -    char *addr_string_range_end;
> +    struct event_location *location_range_end;
>  
>      /* Architecture we used to set the breakpoint.  */
>      struct gdbarch *gdbarch;
> @@ -1293,10 +1296,30 @@ enum breakpoint_create_flags
>      CREATE_BREAKPOINT_FLAGS_INSERTED = 1 << 0
>    };
>  
> -extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
> +/* Set a breakpoint.  This function is shared between CLI and MI functions
> +   for setting a breakpoint at LOCATION.
> +
> +   This function has two major modes of operations, selected by the
> +   PARSE_EXTRA parameter.
> +
> +   If PARSE_EXTRA is zero, LOCATION is just the breakpoint's location,
> +   with condition, thread, and extra string specified by the COND_STRING,
> +   THREAD, and EXTRA_STRING parameters.
> +
> +   If PARSE_EXTRA is non-zero, this function will attempt to extract
> +   the condition, thread, and extra string from EXTRA_STRING, ignoring
> +   the similarly named parameters.
> +
> +   If INTERNAL is non-zero, the breakpoint number will be allocated
> +   from the internal breakpoint count.
> +
> +   Returns true if any breakpoint was created; false otherwise.  */
> +
> +extern int create_breakpoint (struct gdbarch *gdbarch,
> +			      const struct event_location *location,
>  			      char *cond_string, int thread,
>  			      char *extra_string,
> -			      int parse_arg,
> +			      int parse_extra,
>  			      int tempflag, enum bptype wanted_type,
>  			      int ignore_count,
>  			      enum auto_boolean pending_break_support,
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index 2ec2dd3..e9664c9 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -38,6 +38,7 @@
>  #include "disasm.h"
>  #include "tracepoint.h"
>  #include "filestuff.h"
> +#include "location.h"
>  
>  #include "ui-out.h"
>  
> @@ -782,7 +783,6 @@ edit_command (char *arg, int from_tty)
>    struct symtabs_and_lines sals;
>    struct symtab_and_line sal;
>    struct symbol *sym;
> -  char *arg1;
>    char *editor;
>    char *p;
>    const char *fn;
> @@ -804,21 +804,28 @@ edit_command (char *arg, int from_tty)
>      }
>    else
>      {
> -      /* Now should only be one argument -- decode it in SAL.  */
> +      struct cleanup *cleanup;
> +      struct event_location *location;
> +      char *arg1;
>  
> +      /* Now should only be one argument -- decode it in SAL.  */
>        arg1 = arg;
> -      sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
> +      location = string_to_event_location (&arg1, current_language);
> +      cleanup = make_cleanup_delete_event_location (location);
> +      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
>  
>        filter_sals (&sals);
>        if (! sals.nelts)
>  	{
>  	  /*  C++  */
> +	  do_cleanups (cleanup);
>  	  return;
>  	}
>        if (sals.nelts > 1)
>  	{
>  	  ambiguous_line_spec (&sals);
>  	  xfree (sals.sals);
> +	  do_cleanups (cleanup);
>  	  return;
>  	}
>  
> @@ -860,6 +867,7 @@ edit_command (char *arg, int from_tty)
>  
>        if (sal.symtab == 0)
>          error (_("No line number known for %s."), arg);
> +      do_cleanups (cleanup);
>      }
>  
>    if ((editor = (char *) getenv ("EDITOR")) == NULL)
> @@ -888,6 +896,9 @@ list_command (char *arg, int from_tty)
>    int dummy_beg = 0;
>    int linenum_beg = 0;
>    char *p;
> +  struct cleanup *cleanup;
> +
> +  cleanup = make_cleanup (null_cleanup, NULL);
>  
>    /* Pull in the current default source line if necessary.  */
>    if (arg == 0 || arg[0] == '+' || arg[0] == '-')
> @@ -951,15 +962,24 @@ list_command (char *arg, int from_tty)
>      dummy_beg = 1;
>    else
>      {
> -      sals = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
> +      struct event_location *location;
> +
> +      location = string_to_event_location (&arg1, current_language);
> +      make_cleanup_delete_event_location (location);
> +      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
>  
>        filter_sals (&sals);
>        if (!sals.nelts)
> -	return;			/*  C++  */
> +	{
> +	  /*  C++  */
> +	  do_cleanups (cleanup);
> +	  return;
> +	}
>        if (sals.nelts > 1)
>  	{
>  	  ambiguous_line_spec (&sals);
>  	  xfree (sals.sals);
> +	  do_cleanups (cleanup);
>  	  return;
>  	}
>  
> @@ -984,18 +1004,28 @@ list_command (char *arg, int from_tty)
>  	dummy_end = 1;
>        else
>  	{
> +	  struct event_location *location;
> +
> +	  location = string_to_event_location (&arg1, current_language);
> +	  make_cleanup_delete_event_location (location);
>  	  if (dummy_beg)
> -	    sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE, 0, 0);
> +	    sals_end = decode_line_1 (location,
> +				      DECODE_LINE_LIST_MODE, 0, 0);
>  	  else
> -	    sals_end = decode_line_1 (&arg1, DECODE_LINE_LIST_MODE,
> +	    sals_end = decode_line_1 (location, DECODE_LINE_LIST_MODE,
>  				      sal.symtab, sal.line);
> +
>  	  filter_sals (&sals_end);
>  	  if (sals_end.nelts == 0)
> -	    return;
> +	    {
> +	      do_cleanups (cleanup);
> +	      return;
> +	    }
>  	  if (sals_end.nelts > 1)
>  	    {
>  	      ambiguous_line_spec (&sals_end);
>  	      xfree (sals_end.sals);
> +	      do_cleanups (cleanup);
>  	      return;
>  	    }
>  	  sal_end = sals_end.sals[0];
> @@ -1076,6 +1106,7 @@ list_command (char *arg, int from_tty)
>  			 ? sal.line + get_lines_to_list ()
>  			 : sal_end.line + 1),
>  			0);
> +  do_cleanups (cleanup);
>  }
>  
>  /* Subroutine of disassemble_command to simplify it.
> diff --git a/gdb/elfread.c b/gdb/elfread.c
> index 4b97b04..acf5112 100644
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -45,6 +45,7 @@
>  #include "bcache.h"
>  #include "gdb_bfd.h"
>  #include "build-id.h"
> +#include "location.h"
>  
>  extern void _initialize_elfread (void);
>  
> @@ -1077,7 +1078,8 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
>    resolved_pc = gdbarch_addr_bits_remove (gdbarch, resolved_pc);
>  
>    gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
> -  elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
> +  elf_gnu_ifunc_record_cache (event_location_to_string (b->location),
> +			      resolved_pc);
>  
>    sal = find_pc_line (resolved_pc, 0);
>    sals.nelts = 1;
> diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
> index ad853ed..b46f67d 100644
> --- a/gdb/guile/scm-breakpoint.c
> +++ b/gdb/guile/scm-breakpoint.c
> @@ -31,6 +31,7 @@
>  #include "arch-utils.h"
>  #include "language.h"
>  #include "guile-internal.h"
> +#include "location.h"
>  
>  /* The <gdb:breakpoint> smob.
>     N.B.: The name of this struct is known to breakpoint.h.
> @@ -173,6 +174,8 @@ bpscm_print_breakpoint_smob (SCM self, SCM port, scm_print_state *pstate)
>    /* Careful, the breakpoint may be invalid.  */
>    if (b != NULL)
>      {
> +      const char *str;
> +
>        gdbscm_printf (port, " %s %s %s",
>  		     bpscm_type_to_string (b->type),
>  		     bpscm_enable_state_to_string (b->enable_state),
> @@ -181,8 +184,9 @@ bpscm_print_breakpoint_smob (SCM self, SCM port, scm_print_state *pstate)
>        gdbscm_printf (port, " hit:%d", b->hit_count);
>        gdbscm_printf (port, " ignore:%d", b->ignore_count);
>  
> -      if (b->addr_string != NULL)
> -	gdbscm_printf (port, " @%s", b->addr_string);
> +      str = event_location_to_string (b->location);
> +      if (str != NULL)
> +	gdbscm_printf (port, " @%s", str);
>      }
>  
>    scm_puts (">", port);
> @@ -408,6 +412,9 @@ gdbscm_register_breakpoint_x (SCM self)
>    breakpoint_smob *bp_smob
>      = bpscm_get_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
>    struct gdb_exception except = exception_none;
> +  char *location, *copy;
> +  struct event_location *eloc;
> +  struct cleanup *cleanup;
>  
>    /* We only support registering breakpoints created with make-breakpoint.  */
>    if (!bp_smob->is_scheme_bkpt)
> @@ -417,10 +424,13 @@ gdbscm_register_breakpoint_x (SCM self)
>      scm_misc_error (FUNC_NAME, _("breakpoint is already registered"), SCM_EOL);
>  
>    pending_breakpoint_scm = self;
> +  location = bp_smob->spec.location;
> +  copy = location;
> +  eloc = new_linespec_location (&copy);
> +  cleanup = make_cleanup_delete_event_location (eloc);
>  
>    TRY
>      {
> -      char *location = bp_smob->spec.location;
>        int internal = bp_smob->spec.is_internal;
>  
>        switch (bp_smob->spec.type)
> @@ -428,7 +438,7 @@ gdbscm_register_breakpoint_x (SCM self)
>  	case bp_breakpoint:
>  	  {
>  	    create_breakpoint (get_current_arch (),
> -			       location, NULL, -1, NULL,
> +			       eloc, NULL, -1, NULL,
>  			       0,
>  			       0, bp_breakpoint,
>  			       0,
> @@ -464,6 +474,7 @@ gdbscm_register_breakpoint_x (SCM self)
>    /* Ensure this gets reset, even if there's an error.  */
>    pending_breakpoint_scm = SCM_BOOL_F;
>    GDBSCM_HANDLE_GDB_EXCEPTION (except);
> +  do_cleanups (cleanup);
>  
>    return SCM_UNSPECIFIED;
>  }
> @@ -819,12 +830,12 @@ gdbscm_breakpoint_location (SCM self)
>  {
>    breakpoint_smob *bp_smob
>      = bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
> -  char *str;
> +  const char *str;
>  
>    if (bp_smob->bp->type != bp_breakpoint)
>      return SCM_BOOL_F;
>  
> -  str = bp_smob->bp->addr_string;
> +  str = event_location_to_string (bp_smob->bp->location);
>    if (! str)
>      str = "";
>  
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index a480be1..5949594 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -43,6 +43,7 @@
>  #include "filenames.h"
>  #include "ada-lang.h"
>  #include "stack.h"
> +#include "location.h"
>  
>  typedef struct symbol *symbolp;
>  DEF_VEC_P (symbolp);
> @@ -281,8 +282,8 @@ struct ls_parser
>      const char *saved_arg;
>  
>      /* Head of the input stream.  */
> -    const char **stream;
> -#define PARSER_STREAM(P) (*(P)->lexer.stream)
> +    const char *stream;
> +#define PARSER_STREAM(P) ((P)->lexer.stream)
>  
>      /* The current token.  */
>      linespec_token current;
> @@ -315,7 +316,7 @@ static CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
>  
>  static struct symtabs_and_lines decode_objc (struct linespec_state *self,
>  					     linespec_p ls,
> -					     const char **argptr);
> +					     const char *arg);
>  
>  static VEC (symtab_ptr) *symtabs_from_filename (const char *);
>  
> @@ -1785,21 +1786,29 @@ linespec_parse_basic (linespec_parser *parser)
>     STATE->canonical.  */
>  
>  static void
> -canonicalize_linespec (struct linespec_state *state, linespec_p ls)
> +canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
>  {
> +  char *tmp;
> +
>    /* If canonicalization was not requested, no need to do anything.  */
>    if (!state->canonical)
>      return;
>  
>    /* Shortcut expressions, which can only appear by themselves.  */
>    if (ls->expression != NULL)
> -    state->canonical->addr_string = xstrdup (ls->expression);
> +    {
> +      tmp = ASTRDUP (ls->expression);
> +      state->canonical->location = new_linespec_location (&tmp);
> +    }
>    else
>      {
>        struct ui_file *buf;
>        int need_colon = 0;
> +      struct cleanup *cleanup;
>  
>        buf = mem_fileopen ();
> +      cleanup = make_cleanup_ui_file_delete (buf);
> +
>        if (ls->source_filename)
>  	{
>  	  fputs_unfiltered (ls->source_filename, buf);
> @@ -1848,8 +1857,10 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
>  			    ls->line_offset.offset);
>  	}
>  
> -      state->canonical->addr_string = ui_file_xstrdup (buf, NULL);
> -      ui_file_delete (buf);
> +      tmp = ui_file_xstrdup (buf, NULL);
> +      make_cleanup (xfree, tmp);
> +      state->canonical->location = new_linespec_location (&tmp);
> +      do_cleanups (cleanup);
>      }
>  }
>  
> @@ -2117,8 +2128,6 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
>  }
>  
>  /* Parse a string that specifies a linespec.
> -   Pass the address of a char * variable; that variable will be
> -   advanced over the characters actually parsed.
>  
>     The basic grammar of linespecs:
>  
> @@ -2167,10 +2176,10 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
>     if no file is validly specified.  Callers must check that.
>     Also, the line number returned may be invalid.  */
>  
> -/* Parse the linespec in ARGPTR.  */
> +/* Parse the linespec in ARG.  */
>  
>  static struct symtabs_and_lines
> -parse_linespec (linespec_parser *parser, const char **argptr)
> +parse_linespec (linespec_parser *parser, const char *arg)
>  {
>    linespec_token token;
>    struct symtabs_and_lines values;
> @@ -2181,30 +2190,30 @@ parse_linespec (linespec_parser *parser, const char **argptr)
>       IDEs to work around bugs in the previous parser by quoting
>       the entire linespec, so we attempt to deal with this nicely.  */
>    parser->is_quote_enclosed = 0;
> -  if (!is_ada_operator (*argptr)
> -      && strchr (linespec_quote_characters, **argptr) != NULL)
> +  if (!is_ada_operator (arg)
> +      && strchr (linespec_quote_characters, *arg) != NULL)
>      {
>        const char *end;
>  
> -      end = skip_quote_char (*argptr + 1, **argptr);
> +      end = skip_quote_char (arg + 1, *arg);
>        if (end != NULL && is_closing_quote_enclosed (end))
>  	{
> -	  /* Here's the special case.  Skip ARGPTR past the initial
> +	  /* Here's the special case.  Skip ARG past the initial
>  	     quote.  */
> -	  ++(*argptr);
> +	  ++arg;
>  	  parser->is_quote_enclosed = 1;
>  	}
>      }
>  
> -  parser->lexer.saved_arg = *argptr;
> -  parser->lexer.stream = argptr;
> +  parser->lexer.saved_arg = arg;
> +  parser->lexer.stream = arg;
>  
>    /* Initialize the default symtab and line offset.  */
>    initialize_defaults (&PARSER_STATE (parser)->default_symtab,
>  		       &PARSER_STATE (parser)->default_line);
>  
>    /* Objective-C shortcut.  */
> -  values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), argptr);
> +  values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg);
>    if (values.sals != NULL)
>      return values;
>  
> @@ -2390,6 +2399,7 @@ linespec_parser_new (linespec_parser *parser,
>  		     int default_line,
>  		     struct linespec_result *canonical)
>  {
> +  memset (parser, 0, sizeof (linespec_parser));
>    parser->lexer.current.type = LSTOKEN_CONSUMED;
>    memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
>    PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
> @@ -2443,7 +2453,6 @@ linespec_lex_to_end (char **stringp)
>    linespec_parser parser;
>    struct cleanup *cleanup;
>    linespec_token token;
> -  volatile struct gdb_exception e;
>    const char *orig;
>  
>    if (stringp == NULL || *stringp == NULL)
> @@ -2490,10 +2499,42 @@ linespec_lex_to_end (char **stringp)
>    do_cleanups (cleanup);
>  }
>  
> +/* A helper function for decode_line_full and decode_line_1 to
> +   turn LOCATION into symtabs_and_lines.  */
> +
> +static struct symtabs_and_lines
> +event_location_to_sals (linespec_parser *parser,
> +			const struct event_location *location)
> +{
> +  struct symtabs_and_lines result = {NULL, 0};
> +
> +  switch (event_location_type (location))
> +    {
> +    case LINESPEC_LOCATION:
> +      {
> +	TRY
> +	  {
> +	    result = parse_linespec (parser, get_linespec_location (location));
> +	  }
> +	CATCH (except, RETURN_MASK_ERROR)
> +	  {
> +	    throw_exception (except);
> +	  }
> +	END_CATCH
> +      }
> +      break;
> +
> +    default:
> +      gdb_assert_not_reached ("unhandled event location type");
> +    }
> +
> +  return result;
> +}
> +
>  /* See linespec.h.  */
>  
>  void
> -decode_line_full (char **argptr, int flags,
> +decode_line_full (const struct event_location *location, int flags,
>  		  struct symtab *default_symtab,
>  		  int default_line, struct linespec_result *canonical,
>  		  const char *select_mode,
> @@ -2504,7 +2545,6 @@ decode_line_full (char **argptr, int flags,
>    VEC (const_char_ptr) *filters = NULL;
>    linespec_parser parser;
>    struct linespec_state *state;
> -  const char *copy, *orig;
>  
>    gdb_assert (canonical != NULL);
>    /* The filter only makes sense for 'all'.  */
> @@ -2520,13 +2560,10 @@ decode_line_full (char **argptr, int flags,
>    cleanups = make_cleanup (linespec_parser_delete, &parser);
>    save_current_program_space ();
>  
> -  orig = copy = *argptr;
> -  result = parse_linespec (&parser, &copy);
> -  *argptr += copy - orig;
> +  result = event_location_to_sals (&parser, location);
>    state = PARSER_STATE (&parser);
>  
>    gdb_assert (result.nelts == 1 || canonical->pre_expanded);
> -  gdb_assert (canonical->addr_string != NULL);
>    canonical->pre_expanded = 1;
>  
>    /* Arrange for allocated canonical names to be freed.  */
> @@ -2570,23 +2607,20 @@ decode_line_full (char **argptr, int flags,
>  /* See linespec.h.  */
>  
>  struct symtabs_and_lines
> -decode_line_1 (char **argptr, int flags,
> +decode_line_1 (const struct event_location *location, int flags,
>  	       struct symtab *default_symtab,
>  	       int default_line)
>  {
>    struct symtabs_and_lines result;
>    linespec_parser parser;
>    struct cleanup *cleanups;
> -  const char *copy, *orig;
>  
>    linespec_parser_new (&parser, flags, current_language, default_symtab,
>  		       default_line, NULL);
>    cleanups = make_cleanup (linespec_parser_delete, &parser);
>    save_current_program_space ();
>  
> -  orig = copy = *argptr;
> -  result = parse_linespec (&parser, &copy);
> -  *argptr += copy - orig;
> +  result = event_location_to_sals (&parser, location);
>  
>    do_cleanups (cleanups);
>    return result;
> @@ -2599,6 +2633,8 @@ decode_line_with_current_source (char *string, int flags)
>  {
>    struct symtabs_and_lines sals;
>    struct symtab_and_line cursal;
> +  struct event_location *location;
> +  struct cleanup *cleanup;
>  
>    if (string == 0)
>      error (_("Empty line specification."));
> @@ -2607,11 +2643,15 @@ decode_line_with_current_source (char *string, int flags)
>       and get a default source symtab+line or it will recursively call us!  */
>    cursal = get_current_source_symtab_and_line ();
>  
> -  sals = decode_line_1 (&string, flags,
> +  location = string_to_event_location (&string, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
> +  sals = decode_line_1 (location, flags,
>  			cursal.symtab, cursal.line);
>  
>    if (*string)
>      error (_("Junk at end of line specification: %s"), string);
> +
> +  do_cleanups (cleanup);
>    return sals;
>  }
>  
> @@ -2621,19 +2661,25 @@ struct symtabs_and_lines
>  decode_line_with_last_displayed (char *string, int flags)
>  {
>    struct symtabs_and_lines sals;
> +  struct event_location *location;
> +  struct cleanup *cleanup;
>  
>    if (string == 0)
>      error (_("Empty line specification."));
>  
> +  location = string_to_event_location (&string, current_language);
> +  cleanup = make_cleanup_delete_event_location (location);
>    if (last_displayed_sal_is_valid ())
> -    sals = decode_line_1 (&string, flags,
> +    sals = decode_line_1 (location, flags,
>  			  get_last_displayed_symtab (),
>  			  get_last_displayed_line ());
>    else
> -    sals = decode_line_1 (&string, flags, (struct symtab *) NULL, 0);
> +    sals = decode_line_1 (location, flags, (struct symtab *) NULL, 0);
>  
>    if (*string)
>      error (_("Junk at end of line specification: %s"), string);
> +
> +  do_cleanups (cleanup);
>    return sals;
>  }
>  
> @@ -2686,7 +2732,7 @@ linespec_expression_to_pc (const char **exp_ptr)
>     the existing C++ code to let the user choose one.  */
>  
>  static struct symtabs_and_lines
> -decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
> +decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
>  {
>    struct collect_info info;
>    VEC (const_char_ptr) *symbol_names = NULL;
> @@ -2704,7 +2750,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
>    values.nelts = 0;
>    values.sals = NULL;
>  
> -  new_argptr = find_imps (*argptr, &symbol_names); 
> +  new_argptr = find_imps (arg, &symbol_names);
>    if (VEC_empty (const_char_ptr, symbol_names))
>      {
>        do_cleanups (cleanup);
> @@ -2718,9 +2764,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
>      {
>        char *saved_arg;
>  
> -      saved_arg = alloca (new_argptr - *argptr + 1);
> -      memcpy (saved_arg, *argptr, new_argptr - *argptr);
> -      saved_arg[new_argptr - *argptr] = '\0';
> +      saved_arg = alloca (new_argptr - arg + 1);
> +      memcpy (saved_arg, arg, new_argptr - arg);
> +      saved_arg[new_argptr - arg] = '\0';
>  
>        ls->function_name = xstrdup (saved_arg);
>        ls->function_symbols = info.result.symbols;
> @@ -2729,17 +2775,23 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
>  
>        if (self->canonical)
>  	{
> +	  char *str;
> +
>  	  self->canonical->pre_expanded = 1;
> +
>  	  if (ls->source_filename)
> -	    self->canonical->addr_string
> -	      = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
> +	    {
> +	      str = xstrprintf ("%s:%s",
> +				ls->source_filename, saved_arg);
> +	    }
>  	  else
> -	    self->canonical->addr_string = xstrdup (saved_arg);
> +	    str = xstrdup (saved_arg);
> +
> +	  make_cleanup (xfree, str);
> +	  self->canonical->location = new_linespec_location (&str);
>  	}
>      }
>  
> -  *argptr = new_argptr;
> -
>    do_cleanups (cleanup);
>  
>    return values;
> @@ -3819,7 +3871,7 @@ destroy_linespec_result (struct linespec_result *ls)
>    int i;
>    struct linespec_sals *lsal;
>  
> -  xfree (ls->addr_string);
> +  delete_event_location (ls->location);
>    for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
>      {
>        xfree (lsal->canonical);
> diff --git a/gdb/linespec.h b/gdb/linespec.h
> index 77ec46d..840bae5 100644
> --- a/gdb/linespec.h
> +++ b/gdb/linespec.h
> @@ -39,7 +39,7 @@ enum decode_line_flags
>  
>  struct linespec_sals
>  {
> -  /* This is the linespec corresponding to the sals contained in this
> +  /* This is the location corresponding to the sals contained in this
>       object.  It can be passed as the FILTER argument to future calls
>       to decode_line_full.  This is freed by
>       destroy_linespec_result.  */
> @@ -71,9 +71,9 @@ struct linespec_result
>       object.  */
>    int pre_expanded;
>  
> -  /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
> +  /* If PRE_EXPANDED is non-zero, this is set to the location entered
>       by the user.  This will be freed by destroy_linespec_result.  */
> -  char *addr_string;
> +  struct event_location *location;
>  
>    /* The sals.  The vector will be freed by
>       destroy_linespec_result.  */
> @@ -96,10 +96,10 @@ extern struct cleanup *
>  /* Decode a linespec using the provided default symtab and line.  */
>  
>  extern struct symtabs_and_lines
> -	decode_line_1 (char **argptr, int flags,
> +	decode_line_1 (const struct event_location *location, int flags,
>  		       struct symtab *default_symtab, int default_line);
>  
> -/* Parse *ARGPTR as a linespec and return results.  This is the "full"
> +/* Parse LOCATION and return results.  This is the "full"
>     interface to this module, which handles multiple results
>     properly.
>  
> @@ -135,7 +135,7 @@ extern struct symtabs_and_lines
>     strcmp sense) to FILTER will be returned; all others will be
>     filtered out.  */
>  
> -extern void decode_line_full (char **argptr, int flags,
> +extern void decode_line_full (const struct event_location *location, int flags,
>  			      struct symtab *default_symtab, int default_line,
>  			      struct linespec_result *canonical,
>  			      const char *select_mode,
> diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
> index 186f807..c8c988d 100644
> --- a/gdb/mi/mi-cmd-break.c
> +++ b/gdb/mi/mi-cmd-break.c
> @@ -28,6 +28,9 @@
>  #include "observer.h"
>  #include "mi-main.h"
>  #include "mi-cmd-break.h"
> +#include "language.h"
> +#include "location.h"
> +#include "linespec.h"
>  #include "gdb_obstack.h"
>  #include <ctype.h>
>  
> @@ -177,6 +180,7 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
>    int tracepoint = 0;
>    struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
>    enum bptype type_wanted;
> +  struct event_location *location;
>    struct breakpoint_ops *ops;
>    char *extra_string = NULL;
>  
> @@ -287,7 +291,13 @@ mi_cmd_break_insert_1 (int dprintf, char *command, char **argv, int argc)
>        ops = &bkpt_breakpoint_ops;
>      }
>  
> -  create_breakpoint (get_current_arch (), address, condition, thread,
> +  location = string_to_event_location (&address, current_language);
> +  make_cleanup_delete_event_location (location);
> +
> +  if (*address)
> +    error (_("Garbage '%s' at end of location"), address);
> +
> +  create_breakpoint (get_current_arch (), location, condition, thread,
>  		     extra_string,
>  		     0 /* condition and thread are valid.  */,
>  		     temp_p, type_wanted,
> diff --git a/gdb/probe.c b/gdb/probe.c
> index dce2b25..8366220 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -33,6 +33,7 @@
>  #include "value.h"
>  #include "ax.h"
>  #include "ax-gdb.h"
> +#include "location.h"
>  #include <ctype.h>
>  
>  typedef struct bound_probe bound_probe_s;
> @@ -43,23 +44,24 @@ DEF_VEC_O (bound_probe_s);
>  /* See definition in probe.h.  */
>  
>  struct symtabs_and_lines
> -parse_probes (char **argptr, struct linespec_result *canonical)
> +parse_probes (const struct event_location *location,
> +	      struct linespec_result *canonical)
>  {
> -  char *arg_start, *arg_end, *arg;
> +  char *arg_end, *arg;
>    char *objfile_namestr = 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 = *argptr;
> +  arg_start = get_linespec_location (location);
>  
> -  cs = *argptr;
> +  cs = arg_start;
>    probe_ops = probe_linespec_to_ops (&cs);
>    if (probe_ops == NULL)
>      error (_("'%s' is not a probe linespec"), arg_start);
> @@ -170,12 +172,15 @@ parse_probes (char **argptr, struct linespec_result *canonical)
>  
>    if (canonical)
>      {
> +      char *canon;
> +
> +      canon = savestring (arg_start, arg_end - arg_start);
> +      make_cleanup (xfree, canon);
>        canonical->special_display = 1;
>        canonical->pre_expanded = 1;
> -      canonical->addr_string = savestring (*argptr, arg_end - *argptr);
> +      canonical->location = new_linespec_location (&canon);
>      }
>  
> -  *argptr = arg_end;
>    do_cleanups (cleanup);
>  
>    return result;
> diff --git a/gdb/probe.h b/gdb/probe.h
> index e8d5dfe..c058a38 100644
> --- a/gdb/probe.h
> +++ b/gdb/probe.h
> @@ -20,6 +20,8 @@
>  #if !defined (PROBE_H)
>  #define PROBE_H 1
>  
> +struct event_location;
> +
>  #include "gdb_vecs.h"
>  
>  /* Definition of a vector of probes.  */
> @@ -219,9 +221,9 @@ struct bound_probe
>    };
>  
>  /* A helper for linespec that decodes a probe specification.  It returns a
> -   symtabs_and_lines object and updates *ARGPTR or throws an error.  */
> +   symtabs_and_lines object and updates LOC or throws an error.  */
>  
> -extern struct symtabs_and_lines parse_probes (char **argptr,
> +extern struct symtabs_and_lines parse_probes (const struct event_location *loc,
>  					      struct linespec_result *canon);
>  
>  /* Helper function to register the proper probe_ops to a newly created probe.
> diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
> index 42a8596..30619dc 100644
> --- a/gdb/python/py-breakpoint.c
> +++ b/gdb/python/py-breakpoint.c
> @@ -30,6 +30,7 @@
>  #include "ada-lang.h"
>  #include "arch-utils.h"
>  #include "language.h"
> +#include "location.h"
>  
>  /* Number of live breakpoints.  */
>  static int bppy_live;
> @@ -380,7 +381,7 @@ bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
>  static PyObject *
>  bppy_get_location (PyObject *self, void *closure)
>  {
> -  char *str;
> +  const char *str;
>    gdbpy_breakpoint_object *obj = (gdbpy_breakpoint_object *) self;
>  
>    BPPY_REQUIRE_VALID (obj);
> @@ -388,8 +389,7 @@ bppy_get_location (PyObject *self, void *closure)
>    if (obj->bp->type != bp_breakpoint)
>      Py_RETURN_NONE;
>  
> -  str = obj->bp->addr_string;
> -
> +  str = event_location_to_string (obj->bp->location);
>    if (! str)
>      str = "";
>    return PyString_Decode (str, strlen (str), host_charset (), NULL);
> @@ -670,8 +670,12 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>  	{
>  	case bp_breakpoint:
>  	  {
> +	    struct event_location *location;
> +
> +	    location = new_linespec_location (&copy);
> +	    make_cleanup_delete_event_location (location);
>  	    create_breakpoint (python_gdbarch,
> -			       copy, NULL, -1, NULL,
> +			       location, NULL, -1, NULL,
>  			       0,
>  			       temporary_bp, bp_breakpoint,
>  			       0,
> diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
> index 34e9643..2160ef5 100644
> --- a/gdb/python/py-finishbreakpoint.c
> +++ b/gdb/python/py-finishbreakpoint.c
> @@ -29,6 +29,7 @@
>  #include "observer.h"
>  #include "inferior.h"
>  #include "block.h"
> +#include "location.h"
>  
>  /* Function that is called when a Python finish bp is found out of scope.  */
>  static char * const outofscope_func = "out_of_scope";
> @@ -166,7 +167,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>    PyObject *internal = NULL;
>    int internal_bp = 0;
>    CORE_ADDR finish_pc, pc;
> -  char *addr_str, small_buf[100];
> +  char small_buf[100], *p;
>    struct symbol *function;
>  
>    if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
> @@ -293,13 +294,17 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>  
>    TRY
>      {
> +      struct event_location *location;
> +      struct cleanup *back_to;
> +
>        /* Set a breakpoint on the return address.  */
>        finish_pc = get_frame_pc (prev_frame);
>        xsnprintf (small_buf, sizeof (small_buf), "*%s", hex_string (finish_pc));
> -      addr_str = small_buf;
> -
> +      p = small_buf;
> +      location = new_linespec_location (&p);
> +      back_to = make_cleanup_delete_event_location (location);
>        create_breakpoint (python_gdbarch,
> -                         addr_str, NULL, thread, NULL,
> +                         location, NULL, thread, NULL,
>                           0,
>                           1 /*temp_flag*/,
>                           bp_breakpoint,
> @@ -307,6 +312,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>                           AUTO_BOOLEAN_TRUE,
>                           &bkpt_breakpoint_ops,
>                           0, 1, internal_bp, 0);
> +      do_cleanups (back_to);
>      }
>    CATCH (except, RETURN_MASK_ALL)
>      {
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 4f88b0e..c28f98b 100644
> --- a/gdb/python/python.c
> +++ b/gdb/python/python.c
> @@ -34,6 +34,7 @@
>  #include "extension-priv.h"
>  #include "cli/cli-utils.h"
>  #include <ctype.h>
> +#include "location.h"
>  
>  /* Declared constants and enum for python stack printing.  */
>  static const char python_excp_none[] = "none";
> @@ -724,12 +725,12 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>    struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to
>  						  appease gcc.  */
>    struct symtab_and_line sal;
> -  const char *arg = NULL;
> -  char *copy_to_free = NULL, *copy = NULL;
> +  char *arg = NULL;
>    struct cleanup *cleanups;
>    PyObject *result = NULL;
>    PyObject *return_result = NULL;
>    PyObject *unparsed = NULL;
> +  struct event_location *location;
>  
>    if (! PyArg_ParseTuple (args, "|s", &arg))
>      return NULL;
> @@ -738,14 +739,16 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>  
>    sals.sals = NULL;
>  
> +  if (arg != NULL)
> +    {
> +      location = new_linespec_location (&arg);
> +      make_cleanup_delete_event_location (location);
> +    }
> +
>    TRY
>      {
>        if (arg)
> -	{
> -	  copy = xstrdup (arg);
> -	  copy_to_free = copy;
> -	  sals = decode_line_1 (&copy, 0, 0, 0);
> -	}
> +	sals = decode_line_1 (location, 0, 0, 0);
>        else
>  	{
>  	  set_default_source_symtab_and_line ();
> @@ -761,10 +764,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>    END_CATCH
>  
>    if (sals.sals != NULL && sals.sals != &sal)
> -    {
> -      make_cleanup (xfree, copy_to_free);
> -      make_cleanup (xfree, sals.sals);
> -    }
> +    make_cleanup (xfree, sals.sals);
>  
>    if (except.reason < 0)
>      {
> @@ -808,9 +808,9 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>        goto error;
>      }
>  
> -  if (copy && strlen (copy) > 0)
> +  if (arg != NULL && strlen (arg) > 0)
>      {
> -      unparsed = PyString_FromString (copy);
> +      unparsed = PyString_FromString (arg);
>        if (unparsed == NULL)
>  	{
>  	  Py_DECREF (result);
> diff --git a/gdb/remote.c b/gdb/remote.c
> index 3b2325f..65536e8 100644
> --- a/gdb/remote.c
> +++ b/gdb/remote.c
> @@ -44,6 +44,7 @@
>  #include "gdb_bfd.h"
>  #include "filestuff.h"
>  #include "rsp-low.h"
> +#include "location.h"
>  
>  #include <sys/time.h>
>  
> @@ -10729,13 +10730,12 @@ remote_download_tracepoint (struct target_ops *self, struct bp_location *loc)
>  
>    if (packet_support (PACKET_TracepointSource) == PACKET_ENABLE)
>      {
> -      if (b->addr_string)
> +      if (b->location != NULL)
>  	{
>  	  strcpy (buf, "QTDPsrc:");
> -	  encode_source_string (b->number, loc->address,
> -				"at", b->addr_string, buf + strlen (buf),
> -				2048 - strlen (buf));
> -
> +	  encode_source_string (b->number, loc->address, "at",
> +				event_location_to_string (b->location),
> +				buf + strlen (buf), 2048 - strlen (buf));
>  	  putpkt (buf);
>  	  remote_get_noisy_reply (&target_buf, &target_buf_size);
>  	  if (strcmp (target_buf, "OK"))
> diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
> index 7e05834..83f4c6e 100644
> --- a/gdb/spu-tdep.c
> +++ b/gdb/spu-tdep.c
> @@ -45,7 +45,7 @@
>  #include "dwarf2-frame.h"
>  #include "ax.h"
>  #include "spu-tdep.h"
> -
> +#include "location.h"
>  
>  /* The list of available "set spu " and "show spu " commands.  */
>  static struct cmd_list_element *setspucmdlist = NULL;
> @@ -1954,8 +1954,10 @@ spu_catch_start (struct objfile *objfile)
>  {
>    struct bound_minimal_symbol minsym;
>    struct compunit_symtab *cust;
> +  char buf[32], *p;
>    CORE_ADDR pc;
> -  char buf[32];
> +  struct event_location *location;
> +  struct cleanup *back_to;
>  
>    /* Do this only if requested by "set spu stop-on-load on".  */
>    if (!spu_stop_on_load_p)
> @@ -2000,7 +2002,10 @@ spu_catch_start (struct objfile *objfile)
>    /* Use a numerical address for the set_breakpoint command to avoid having
>       the breakpoint re-set incorrectly.  */
>    xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
> -  create_breakpoint (get_objfile_arch (objfile), buf /* arg */,
> +  p = buf;
> +  location = new_linespec_location (&p);
> +  back_to = make_cleanup_delete_event_location (location);
> +  create_breakpoint (get_objfile_arch (objfile), location,
>  		     NULL /* cond_string */, -1 /* thread */,
>  		     NULL /* extra_string */,
>  		     0 /* parse_condition_and_thread */, 1 /* tempflag */,
> @@ -2009,6 +2014,7 @@ spu_catch_start (struct objfile *objfile)
>  		     AUTO_BOOLEAN_FALSE /* pending_break_support */,
>  		     &bkpt_breakpoint_ops /* ops */, 0 /* from_tty */,
>  		     1 /* enabled */, 0 /* internal  */, 0);
> +  do_cleanups (back_to);
>  }
>  
>  
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index 7c04ecb..af553a3 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -55,6 +55,7 @@
>  #include "filestuff.h"
>  #include "rsp-low.h"
>  #include "tracefile.h"
> +#include "location.h"
>  
>  /* readline include files */
>  #include "readline/readline.h"
> @@ -2712,14 +2713,22 @@ scope_info (char *args, int from_tty)
>    int j, count = 0;
>    struct gdbarch *gdbarch;
>    int regno;
> +  struct event_location *location;
> +  struct cleanup *back_to;
>  
>    if (args == 0 || *args == 0)
>      error (_("requires an argument (function, "
>  	     "line or *addr) to define a scope"));
>  
> -  sals = decode_line_1 (&args, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
> +  location = string_to_event_location (&args, current_language);
> +  back_to = make_cleanup_delete_event_location (location);
> +  sals = decode_line_1 (location, DECODE_LINE_FUNFIRSTLINE, NULL, 0);
>    if (sals.nelts == 0)
> -    return;		/* Presumably decode_line_1 has already warned.  */
> +    {
> +      /* Presumably decode_line_1 has already warned.  */
> +      do_cleanups (back_to);
> +      return;
> +    }
>  
>    /* Resolve line numbers to PC.  */
>    resolve_sal_pc (&sals.sals[0]);
> @@ -2856,6 +2865,7 @@ scope_info (char *args, int from_tty)
>    if (count <= 0)
>      printf_filtered ("Scope for %s contains no locals or arguments.\n",
>  		     save_args);
> +  do_cleanups (back_to);
>  }
>  
>  /* Helper for trace_dump_command.  Dump the action list starting at
> @@ -3078,7 +3088,7 @@ trace_dump_command (char *args, int from_tty)
>  
>  extern int
>  encode_source_string (int tpnum, ULONGEST addr,
> -		      char *srctype, char *src, char *buf, int buf_size)
> +		      char *srctype, const char *src, char *buf, int buf_size)
>  {
>    if (80 + strlen (srctype) > buf_size)
>      error (_("Buffer too small for source encoding"));
> diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
> index f34be15..549cf61 100644
> --- a/gdb/tracepoint.h
> +++ b/gdb/tracepoint.h
> @@ -298,7 +298,7 @@ extern struct trace_state_variable *
>  extern struct trace_state_variable *create_trace_state_variable (const char *name);
>  
>  extern int encode_source_string (int num, ULONGEST addr,
> -				 char *srctype, char *src,
> +				 char *srctype, const char *src,
>  				 char *buf, int buf_size);
>  
>  extern void parse_trace_status (char *line, struct trace_status *ts);

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 4/9] Explicit locations: introduce address locations
  2015-05-07 18:06 ` [PATCH v4 4/9] Explicit locations: introduce address locations Keith Seitz
@ 2015-05-18  5:45   ` Doug Evans
  0 siblings, 0 replies; 33+ messages in thread
From: Doug Evans @ 2015-05-18  5:45 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch adds support for address locations, of the form "*ADDR".
> [Support for address linespecs has been removed/replaced by this "new"
> location type.] This patch also converts any existing address locations
> from its previous linespec type.
>
> gdb/ChangeLog:
>
> 	* breakpoint.c (create_thread_event_breakpoint): Convert
> 	linespec to address location.
> 	(init_breakpoint_sal): Likewise.
> 	* linespec.c (canonicalize_linespec): Do not handle address
> 	locations here.
> 	(convert_address_location_to_sals): New function; contents moved
> 	from ...
> 	(convert_linespc_to_sals): ... here.
> 	(parse_linespec): Remove address locations from linespec grammar.
> 	Remove handling of address locations.
> 	(linespec_lex_to_end): Remove handling of address linespecs.
> 	(event_location_to_sals): Handle ADDRESS_LOCATION.
> 	(linespec_expression_to_pc): Export.
> 	* linespec.h (linespec_expression_to_pc): Add declaration.
> 	* location.c (struct event_location.u) <address>: New member.
> 	(new_address_location, get_address_location): New functions.
> 	(copy_event_location): Handle address locations.
> 	(delete_event_location): Likewise.
> 	(event_location_to_string): Likewise.
> 	(string_to_event_location): Likewise.
> 	(event_location_empty_p): Likewise.
> 	* location.h (enum event_location_type): Add ADDRESS_LOCATION.
> 	(new_address_location, get_address_location): Declare.
> 	* python/py-finishbreakpoint.c (bpfinishpy_init): Convert linespec
> 	to address location.
> 	* spu-tdep.c (spu_catch_start): Likewise.

LGTM

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 5/9] Explicit locations: introduce probe locations
  2015-05-07 18:06 ` [PATCH v4 5/9] Explicit locations: introduce probe locations Keith Seitz
@ 2015-05-18  5:49   ` Doug Evans
  0 siblings, 0 replies; 33+ messages in thread
From: Doug Evans @ 2015-05-18  5:49 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch adds support for probe locations and converts existing
> probe linespec locations to the new location type.
>
> gdb/ChangeLog:
>
> 	* break-catch-throw.c (re_set_exception_catchpoint): Convert
> 	linespec for stap probe to probe location.
> 	* breakpoint.c (create_longjmp_master_breakpoint): Likewise.
> 	(create_exception_master_breakpoint): Likewise.
> 	(break_command_1): Remove local variable `arg_cp'.
> 	Check location type to set appropriate breakpoint ops methods.
> 	(trace_command): Likewise.
> 	* linespec.c (event_location_to_sals): Assert on probe locations.
> 	* location.c (EL_PROBE): Add macro definition.
> 	(new_probe_location, get_probe_location): New functions.
> 	(copy_event_location): Handle probe locations.
> 	(delete_event_location): Likewise.
> 	(event_location_to_string): Likewise.
> 	(string_to_event_location): Likewise.
> 	(event_location_empty_p): Likewise.
> 	* location.h (enum event_location_type): Add PROBE_LOCATION.
> 	(new_probe_location, get_probe_location): Declare.
> 	* probe.c (parse_probes): Assert that LOCATION is a probe location.
> 	Convert linespec into probe location.

LGTM

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-07 18:06 ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Keith Seitz
@ 2015-05-18  6:13   ` Doug Evans
  2015-05-18 20:14     ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Doug Evans @ 2015-05-18  6:13 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch add support for explicit locations and switches many linespec
> locations to this new location type.  This patch also converts all
> linespec locations entered by the user to an explicit representation
> internally (thus bypassing the linespec parser when resetting the
> breakpoint).
>
> This patch does not introduce any user-visible changes.
>
>
> gdb/ChangeLog:
>
> 	* break-catch-throw.c (re_set_exception_catchpoint): Convert
> 	linespec into explicit location.
> 	* breakpoint.c (create_overlay_breakpoint): Likewise.
> 	(create_longjmp_master_breakpoint): Likewise.
> 	(create_std_terminate_master_breakpoint): Likewise.
> 	(create_exception_master_breakpoint): Likewise.
> 	(create_breakpoint): For pending explicit locations, append extra_string
> 	to the canonical representation.
> 	(update_static_tracepoint): Convert linespec into explicit location.
> 	(location_to_sals): Save the string representation of the location
> 	for pending locations which were resolved.
> 	* linespec.c (enum offset_relative_sign): Move to location.h.
> 	(struct line_offset): Likewise.
> 	(struct linespec) <expression, expr_pc, source_filename>
> 	<function_name, label_name, line_offset>: Replace with ...
> 	<explicit>: ... this.
> 	<is_linespec>: New member.
> 	(PARSER_EXPLICIT): New accessor macro.
> 	(undefined_label_error): New function.
> 	(source_file_not_found_error): New function.
> 	(linespec_parse_basic): The parser result is now an explicit location.
> 	Use PARSER_EXPLICIT to access it.
> 	Use undefined_label_error.
> 	(canonicalize_linespec): Convert canonical linespec into explicit
> 	location.
> 	Move string representation of location to explicit_location_to_linespec
> 	and use it and explicit_location_to_string to save string
> 	representations of the canonical location.
> 	(create_sals_line_offset): `ls' contains an explicit location.
> 	Update all references.
> 	(convert_linespec_to_sals): Likewise.
> 	(convert_explicit_location_to_sals): New function.
> 	(parse_linespec): Use PARSER_EXPLICIT to access the parser
> 	result's explicit location.
> 	(linespec_state_constructor): Initialize is_linespec.
> 	Use PARSER_EXPLICIT.
> 	(linespec_parser_delete): Use PARSER_EXPLICIT to access the parser's
> 	result.
> 	(event_location_to_sals): For linespec locations, set is_linespec.
> 	Handle explicit locations.
> 	(decode_objc): 'ls' contains an explicit location now. Update all
> 	references.
> 	(symtabs_from_filename): Use source_file_not_found_error.
> 	* location.c (struct event_location.u) <explicit>: New member.
> 	(initialize_explicit_location): New function.
> 	(initialize_event_location): Initialize explicit locations.
> 	(new_explicit_location, get_explicit_location)
> 	(get_explicit_location_const): New functions.
> 	(explicit_to_string_internal): New function; most of contents moved
> 	from canonicalize_linespec.
> 	(explicit_location_to_string): New function.
> 	(explicit_location_to_linespec): New function.
> 	(copy_event_location): Handle explicit locations.
> 	(delete_event_location): Likewise.
> 	(event_location_to_string_const): Likewise.
> 	(event_location_empty_p): Likewise.
> 	* location.h (enum offset_relative_sign): Move here from linespec.h.
> 	(struct line_offset): Likewise.
> 	(enum event_location_type): Add EXPLICIT_LOCATION.
> 	(struct explicit_location): New structure.
> 	(explicit_location_to_string): Declare.
> 	(explicit_location_to_linespec): Declare.
> 	(new_explicit_location, get_explicit_locationp
> 	(get_explicit_location_const, initialize_explicit_location): Declare.

LGTM

Not something to be done now, but just curious.
Do we support source file names with spaces?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 7/9] Explicit locations: add UI features for CLI
  2015-05-07 18:06 ` [PATCH v4 7/9] Explicit locations: add UI features for CLI Keith Seitz
@ 2015-05-18  6:55   ` Doug Evans
  2015-05-19 20:41     ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Doug Evans @ 2015-05-18  6:55 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

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

LGTM, with a couple of nits below.

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

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

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

Could other exception types leak oarg here?

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

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 8/9] Explicit locations: MI support for explicit locations
  2015-05-07 18:06 ` [PATCH v4 8/9] Explicit locations: MI support for " Keith Seitz
@ 2015-05-18  7:16   ` Doug Evans
  0 siblings, 0 replies; 33+ messages in thread
From: Doug Evans @ 2015-05-18  7:16 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This patch adds support for explicit locations to MI's -break-insert
> command. The new options, documented in the User Manual, are
> --source, --line, --function, and --label.
>
> gdb/ChangeLog:
>
> 	* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Add support for
> 	explicit locations, options "--source", "--function",
> 	"--label", and "--line".
>
> gdb/testsuite/ChangeLog:
>
> 	* gdb.mi/mi-break.exp (test_explicit_breakpoints): New proc.
> 	(at toplevel): Call test_explicit_breakpoints.
> 	* gdb.mi/mi-dprintf.exp: Add tests for explicit dprintf
> 	breakpoints.
> 	* lib/mi-support.exp (mi_make_breakpoint): Add support for
> 	breakpoint conditions, "-cond".

LGTM

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-18  6:13   ` Doug Evans
@ 2015-05-18 20:14     ` Keith Seitz
  2015-05-19 22:09       ` Pedro Alves
  0 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-18 20:14 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 05/17/2015 11:12 PM, Doug Evans wrote:
> Not something to be done now, but just curious.
> Do we support source file names with spaces?

Good question! My *guess* would be: it should! I certainly remember
fiddling with this, and explicit_location_lex_one does have handling for
it. [The lexer also allows quote-enclosed strings, just like linespec.]

I just tested it (to be certain), and (survey says!):

(gdb) fil ~/tmp/file\ with\ spaces
Reading symbols from ~/tmp/file with spaces...done.
(gdb) b -source file with spaces.c -line 4
Breakpoint 1 at 0x4004fa: file /home/keiths/tmp/file with spaces.c, line 4.
(gdb) r
Starting program: /home/keiths/tmp/file with spaces

Breakpoint 1, main () at /home/keiths/tmp/file with spaces.c:4
4	  return 1;
(gdb)

ls-errs.exp exercises this a bit, too, albeit in a non-obvious way.

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API
  2015-05-17 20:54   ` Doug Evans
@ 2015-05-19 20:41     ` Keith Seitz
  2015-05-19 22:16       ` Pedro Alves
  0 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-19 20:41 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 05/17/2015 01:53 PM, Doug Evans wrote:
>> 	* linespec.c (linespec_lex_to_end): Declare.
> 
> typo: linespec.h

Fixed.

>> diff --git a/gdb/linespec.c b/gdb/linespec.c
>> index d2089b5..a480be1 100644
>> --- a/gdb/linespec.c
>> +++ b/gdb/linespec.c
>> @@ -2435,6 +2435,61 @@ linespec_parser_delete (void *arg)
>>    linespec_state_destructor (PARSER_STATE (parser));
>>  }
>>  
>> +/* See description in linespec.h.  */
>> +
>> +void
>> +linespec_lex_to_end (char **stringp)
>> +{
>> +  linespec_parser parser;
>> +  struct cleanup *cleanup;
>> +  linespec_token token;
>> +  volatile struct gdb_exception e;
>> +  const char *orig;
>> +
>> +  if (stringp == NULL || *stringp == NULL)
>> +    return;
>> +
>> +  linespec_parser_new (&parser, 0, current_language, NULL, 0, NULL);
>> +  cleanup = make_cleanup (linespec_parser_delete, &parser);
>> +  parser.lexer.saved_arg = *stringp;
>> +  PARSER_STREAM (&parser) = orig = *stringp;
>> +
>> +  TRY
>> +    {
>> +      do
>> +	{
>> +	  /* Stop before any comma tokens;  we need it to keep it
>> +	     as the next token in the string.  */
>> +	  token = linespec_lexer_peek_token (&parser);
>> +	  if (token.type == LSTOKEN_COMMA)
>> +	    break;
>> +
>> +	  /* For addresses advance the parser stream past
>> +	     any parsed input and stop lexing.  */
>> +	  if (token.type == LSTOKEN_STRING
>> +	      && *LS_TOKEN_STOKEN (token).ptr == '*')
>> +	    {
>> +	      const char *arg;
>> +
>> +	      arg = *stringp;
>> +	      (void) linespec_expression_to_pc (&arg);
>> +	      PARSER_STREAM (&parser) = arg;
>> +	      break;
>> +	    }
>> +
>> +	  token = linespec_lexer_consume_token (&parser);
>> +	}
>> +      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
>> +    }
>> +  CATCH (e, RETURN_MASK_ERROR)
>> +    {
> 
> I'm guessing I'm missing something here.
> Is the intent to ignore errors here?
>

Yeah, that was the intent. However, I played with this a bit, and while
the end result is identical whether or not an exception is swallowed
here, I am now convinced that doing so is not good.

Fortunately, ls-errs.exp covers this block of code.

As it is right now, new_linespec_location will return the following new
location {type = LINESPEC_LOCATION, u = {addr_string = "\"", ...}, ...}.

This is then passed to the linespec parser which (incidentally IMO)
outputs the correct error.

I've removed the TRY/CATCH/END_CATCH here. It really doesn't make sense
(which I suspect you already knew ;-).

>> +    }
>> +  END_CATCH
>> +
>> +  *stringp += PARSER_STREAM (&parser) - orig;
>> +  do_cleanups (cleanup);
>> +}
>> +
>>  /* See linespec.h.  */
>>  
>>  void
[snip]
>> diff --git a/gdb/location.h b/gdb/location.h
>> new file mode 100644
>> index 0000000..992f21e
>> --- /dev/null
>> +++ b/gdb/location.h
>> @@ -0,0 +1,113 @@
>> +/* Data structures and API for event locations in GDB.
>> +   Copyright (C) 2013-2015 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   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/>.  */
>> +
>> +#ifndef LOCATIONS_H
>> +#define LOCATIONS_H 1
>> +
>> +struct language_defn;
>> +struct event_location;
>> +
>> +/* An enumeration of the various ways to specify a stop event
>> +   location (used with create_breakpoint).  */
>> +
>> +enum event_location_type
>> +{
>> +  /* A traditional linespec.  */
>> +  LINESPEC_LOCATION
>> +};
>> +
>> +/* Return the type of the given event location.  */
>> +
>> +extern enum event_location_type
>> +  event_location_type (const struct event_location *);
>> +
>> +/* Return a string representation of the LOCATION.
>> +   This function may return NULL for unspecified linespecs,
>> +   e.g, LOCATION_LINESPEC and addr_string is NULL.
>> +
>> +   The result is cached in LOCATION.  */
>> +
>> +extern const char *
>> +  event_location_to_string (struct event_location *location);
>> +
>> +/* A const version of event_location_to_string that will not cache
>> +   the resulting string representation.  The result is malloc'd
>> +   and must be freed by the caller.  */
>> +
>> +extern char *
>> +  event_location_to_string_const (const struct event_location *location);
> 
> Note to self: Do we need both non-const and const versions?
> [e.g., treat cached value as mutable in c++ sense?]

Yeah, if we could do something like that in C, that would negate the
need for both versions. As it is, this seemed the easiest (and not
an uncommon) way to deal with this. If you have another option, I'm all
eyes.

>> +
>> +/* Create a new linespec location.  The return result is malloc'd
>> +   and should be freed with delete_event_location.  */
>> +
>> +extern struct event_location *
>> +  new_linespec_location (char **linespec);
>> +
>> +/* Return the linespec location (a string) of the given event_location
>> +   (which must be of type LINESPEC_LOCATION).  */
>> +
>> +extern const char *
>> +  get_linespec_location (const struct event_location *location);
>> +
>> +/* Free an event location and any associated data.  */
>> +
>> +extern void delete_event_location (struct event_location *location);
>> +
>> +/* Make a cleanup to free LOCATION.  */
>> +
>> +extern struct cleanup *
>> +  make_cleanup_delete_event_location (struct event_location *location);
>> +
>> +/* Return a copy of the given SRC location.  */
>> +
>> +extern struct event_location *
>> +  copy_event_location (const struct event_location *src);
>> +
>> +/* Allocate and "copy" the opaque struct event_location.  This is used
>> +   when decoding locations which must parse their inputs.  The return result
>> +   should be freed.  */
>> +
>> +extern struct event_location *
>> +  copy_event_location_tmp (const struct event_location *src);
> 
> This function doesn't exist in this patch.
> 

Doh! It should not exist *at all* anymore! Fixed.

>> +
>> +/* Attempt to convert the input string in *ARGP into an event location.
>> +   ARGP is advanced past any processed input.  Returns a event_location
> 
> nit: an event_location
> 

Fixed.

>> +   (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.
>> +
>> +   The return result must be freed with delete_event_location.  */
>> +
>> +extern struct event_location *
>> +  string_to_event_location (char **argp,
>> +			    const struct language_defn *langauge);
>> +
>> +/* A convenience function for testing for unset locations.  */
>> +
>> +extern int event_location_empty_p (const struct event_location *location);
>> +
>> +/* Set the location's string representation.  If STRING is NULL, clear
>> +   the string representation.  */
>> +
>> +extern void
>> +  set_event_location_string (struct event_location *location,
>> +			     const char *string);
>> +#endif /* LOCATIONS_H */

Thanks for taking another look!

I'll send out new versions of the patches requiring revision shortly.

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 7/9] Explicit locations: add UI features for CLI
  2015-05-18  6:55   ` Doug Evans
@ 2015-05-19 20:41     ` Keith Seitz
  2015-05-27  4:27       ` Doug Evans
  0 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-19 20:41 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 05/17/2015 11:54 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>>  
>> diff --git a/gdb/location.c b/gdb/location.c
>> index 7882b2d..779bcfa 100644
>> --- a/gdb/location.c
>> +++ b/gdb/location.c
>> @@ -442,6 +442,203 @@ event_location_to_string (struct event_location *location)
>>    return EL_STRING (location);
>>  }
>>  
>> +/* A lexer for explicit locations.  This function will advance INP
>> +   past any strings that it lexes.  Returns a malloc'd copy of the
>> +   lexed string or NULL if no lexing was done.  */
>> +
>> +static char *
>> +explicit_location_lex_one (const char **inp,
>> +			   const struct language_defn *language)
>> +{
>> +  const char *start = *inp;
>> +
>> +  if (*start == '\0')
>> +    return NULL;
>> +
>> +  /* If quoted, skip to the ending quote.  */
>> +  if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
>> +    {
>> +      char quote_char = *start;
>> +
>> +      /* If the input is not an Ada operator, skip to the matching
>> +	 closing quote and return the string.  */
>> +      if (!(language->la_language == language_ada
>> +	    && quote_char == '\"' && is_ada_operator (start)))
>> +	{
>> +	  const char *end = find_toplevel_char (start + 1, quote_char);
>> +
>> +	  if (end == NULL)
>> +	    error (_("Unmatched quote, %s."), start);
>> +	  *inp = end + 1;
>> +	  return savestring (start + 1, *inp - start - 2);
>> +	}
>> +    }
>> +
>> +  /* If the input starts with '-' or '+', the string ends with the next
>> +     whitespace.  */
>> +  if (*start == '-' || *start == '+')
>> +    *inp = skip_to_space_const (*inp);
> 
> I suspect this is just following what the existing code does,
> but why not also watch for commas when there's a leading +,-?
> If this is just following code and there's an issue here
> I'd leave it for another day to change.

Good catch. I've implemented this and added a few tests for it.

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

Not that I can see. When any successful argument value is parsed, it is
added to the event_location, which has a cleanup on it which will free
any defined members when an exception occurs.

The only two functions (in this loop) that could throw an exception are
explicit_location_lex_one and linespec_parse_line_offset.

In the former case, the option name has a cleanup when parsing the
value. The value is either saved into the event_location or discarded if
we are going to throw an exception.

linespec_parse_line_offset can throw an error (GENERIC_ERROR), but it is
already caught and memory for oarg is freed. Nothing can generate a
RETURN_QUIT as far as I can tell. Did you have a case specifically in mind?

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 3/9] Explicit locations: use new location API
  2015-05-18  5:21   ` Doug Evans
@ 2015-05-19 21:30     ` Keith Seitz
  0 siblings, 0 replies; 33+ messages in thread
From: Keith Seitz @ 2015-05-19 21:30 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 05/17/2015 10:19 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
>> index 927176f..9449aa5 100644
>> --- a/gdb/break-catch-throw.c
>> +++ b/gdb/break-catch-throw.c
>> @@ -35,6 +35,7 @@
>>  #include "cp-abi.h"
>>  #include "gdb_regex.h"
>>  #include "cp-support.h"
>> +#include "location.h"
>>  
>>  /* Enums for exception-handling support.  */
>>  enum exception_event_kind
>> @@ -210,25 +211,31 @@ re_set_exception_catchpoint (struct breakpoint *self)
>>    struct symtabs_and_lines sals_end = {0};
>>    struct cleanup *cleanup;
>>    enum exception_event_kind kind = classify_exception_breakpoint (self);
>> +  struct event_location *location;
>>  
>>    /* We first try to use the probe interface.  */
>>    TRY
>>      {
>>        char *spec = ASTRDUP (exception_functions[kind].probe);
>>  
> 
> Not something to be done with this patch (let's reach
> closure and get this sucker checked in :-)),
> but IWBN to have an API where we didn't have to do the
> ASTRDUP.  E.g., have new_linespec_location_const or some such.

Understood.

> 
>> -      sals = parse_probes (&spec, NULL);
>> +      location = new_linespec_location (&spec);
>> +      cleanup = make_cleanup_delete_event_location (location);
>> +      sals = parse_probes (location, NULL);
>> +      do_cleanups (cleanup);
>>      }
>>  
>>    CATCH (e, RETURN_MASK_ERROR)
>>      {
>> -
>>        /* Using the probe interface failed.  Let's fallback to the normal
>>  	 catchpoint mode.  */
>>        TRY
>>  	{
>>  	  char *spec = ASTRDUP (exception_functions[kind].function);
>>  
>> -	  self->ops->decode_location (self, &spec, &sals);
>> +	  location = new_linespec_location (&spec);
>> +	  cleanup = make_cleanup_delete_event_location (location);
>> +	  self->ops->decode_location (self, location, &sals);
>> +	  do_cleanups (cleanup);
>>  	}
>>        CATCH (ex, RETURN_MASK_ERROR)
>>  	{
>> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
>> index 31b1f82..549bfd0 100644
>> --- a/gdb/breakpoint.c
>> +++ b/gdb/breakpoint.c
[snip]
>> @@ -13451,19 +13525,28 @@ dprintf_after_condition_true (struct bpstats *bs)
>>     markers (`-m').  */
>>  
>>  static void
>> -strace_marker_create_sals_from_location (char **arg,
>> +strace_marker_create_sals_from_location (const struct event_location *location,
>>  					 struct linespec_result *canonical,
>> -					 enum bptype type_wanted,
>> -					 char *addr_start, char **copy_arg)
>> +					 enum bptype type_wanted)
>>  {
>>    struct linespec_sals lsal;
>> +  const char *arg_start, *arg;
>>  
>> -  lsal.sals = decode_static_tracepoint_spec (arg);
>> +  arg = arg_start = get_linespec_location (location);
>> +  lsal.sals = decode_static_tracepoint_spec (&arg);
>>  
>> -  *copy_arg = savestring (addr_start, *arg - addr_start);
>> +  if (canonical != NULL)
> 
> Why the canonical != NULL test here?
> Outside this "if" below it's assumed canonical != NULL.
> 

Right -- fixed that. Thank you.

>> +    {
>> +      char *str;
>> +      struct cleanup *cleanup;
>>  
>> -  canonical->addr_string = xstrdup (*copy_arg);
>> -  lsal.canonical = xstrdup (*copy_arg);
>> +      str = savestring (arg_start, arg - arg_start);
>> +      cleanup = make_cleanup (xfree, str);
>> +      canonical->location = new_linespec_location (&str);
>> +      do_cleanups (cleanup);
>> +    }
>> +
>> +  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
>>    VEC_safe_push (linespec_sals, canonical->sals, &lsal);
>>  }
>>  
[snip]
>> @@ -14068,22 +14158,21 @@ update_breakpoint_locations (struct breakpoint *b,
>>    update_global_location_list (UGLL_MAY_INSERT);
>>  }
>>  
>> -/* Find the SaL locations corresponding to the given ADDR_STRING.
>> +/* Find the SaL locations corresponding to the given LOCATION.
>>     On return, FOUND will be 1 if any SaL was found, zero otherwise.  */
>>  
>>  static struct symtabs_and_lines
>> -location_to_sals (struct breakpoint *b, char *addr_string, int *found)
>> +location_to_sals (struct breakpoint *b, struct event_location *location,
>> +		  int *found)
>>  {
>> -  char *s;
>>    struct symtabs_and_lines sals = {0};
>>    struct gdb_exception exception = exception_none;
>>  
>>    gdb_assert (b->ops != NULL);
>> -  s = addr_string;
>>  
>>    TRY
>>      {
>> -      b->ops->decode_location (b, &s, &sals);
>> +      b->ops->decode_location (b, location, &sals);
>>      }
>>    CATCH (e, RETURN_MASK_ERROR)
>>      {
>> @@ -14125,12 +14214,13 @@ location_to_sals (struct breakpoint *b, char *addr_string, int *found)
>>  
>>        for (i = 0; i < sals.nelts; ++i)
>>  	resolve_sal_pc (&sals.sals[i]);
>> -      if (b->condition_not_parsed && s && s[0])
>> +      if (b->condition_not_parsed && b->extra_string != NULL)
>>  	{
>>  	  char *cond_string, *extra_string;
>>  	  int thread, task;
>> +	  const char *orig = b->extra_string;
>>  
>> -	  find_condition_and_thread (s, sals.sals[0].pc,
>> +	  find_condition_and_thread (b->extra_string, sals.sals[0].pc,
>>  				     &cond_string, &thread, &task,
>>  				     &extra_string);
>>  	  if (cond_string)
> 
> The code is a bit odd here, at first glance.
> We xfree b->extra_string before assigning a new value,
> but not b->cond_string.
> I'm guessing this is because the latter will always be NULL here.
> Can you add an assert to that effect?  I.e.,
> 
>   gdb_assert (b->cond_string == NULL);

Yeah, you have that right. At least that's how I read and interpreted
that. I've added the assert.

New revision coming your way shortly.

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-18 20:14     ` Keith Seitz
@ 2015-05-19 22:09       ` Pedro Alves
  2015-05-19 22:12         ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Pedro Alves @ 2015-05-19 22:09 UTC (permalink / raw)
  To: Keith Seitz, Doug Evans; +Cc: gdb-patches

On 05/18/2015 09:14 PM, Keith Seitz wrote:
> On 05/17/2015 11:12 PM, Doug Evans wrote:
>> Not something to be done now, but just curious.
>> Do we support source file names with spaces?
> 
> Good question! My *guess* would be: it should! I certainly remember
> fiddling with this, and explicit_location_lex_one does have handling for
> it. [The lexer also allows quote-enclosed strings, just like linespec.]
> 
> I just tested it (to be certain), and (survey says!):
> 
> (gdb) fil ~/tmp/file\ with\ spaces
> Reading symbols from ~/tmp/file with spaces...done.
> (gdb) b -source file with spaces.c -line 4

Eh, do we handle files with spaces without requiring quoting
anywhere else?  The potential for ambiguity makes me a bit nervous
to claim we support that.

> Breakpoint 1 at 0x4004fa: file /home/keiths/tmp/file with spaces.c, line 4.
> (gdb) r
> Starting program: /home/keiths/tmp/file with spaces
> 
> Breakpoint 1, main () at /home/keiths/tmp/file with spaces.c:4
> 4	  return 1;
> (gdb)
> 
> ls-errs.exp exercises this a bit, too, albeit in a non-obvious way.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-19 22:09       ` Pedro Alves
@ 2015-05-19 22:12         ` Keith Seitz
  2015-05-19 22:15           ` Pedro Alves
  0 siblings, 1 reply; 33+ messages in thread
From: Keith Seitz @ 2015-05-19 22:12 UTC (permalink / raw)
  To: Pedro Alves, Doug Evans; +Cc: gdb-patches

On 05/19/2015 03:09 PM, Pedro Alves wrote:

>> (gdb) fil ~/tmp/file\ with\ spaces
>> Reading symbols from ~/tmp/file with spaces...done.
>> (gdb) b -source file with spaces.c -line 4
> 
> Eh, do we handle files with spaces without requiring quoting
> anywhere else?  The potential for ambiguity makes me a bit nervous
> to claim we support that.
> 

The linespec parser doesn't normally require quoting:

Reading symbols from ~/tmp/file with spaces...done.
(gdb) b file with spaces.c:3
Breakpoint 1 at 0x4004fa: file /home/keiths/tmp/file with spaces.c, line 3.

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-19 22:12         ` Keith Seitz
@ 2015-05-19 22:15           ` Pedro Alves
  2015-05-19 22:20             ` Keith Seitz
  0 siblings, 1 reply; 33+ messages in thread
From: Pedro Alves @ 2015-05-19 22:15 UTC (permalink / raw)
  To: Keith Seitz, Doug Evans; +Cc: gdb-patches

On 05/19/2015 11:12 PM, Keith Seitz wrote:
> On 05/19/2015 03:09 PM, Pedro Alves wrote:
> 
>>> (gdb) fil ~/tmp/file\ with\ spaces
>>> Reading symbols from ~/tmp/file with spaces...done.
>>> (gdb) b -source file with spaces.c -line 4
>>
>> Eh, do we handle files with spaces without requiring quoting
>> anywhere else?  The potential for ambiguity makes me a bit nervous
>> to claim we support that.
>>
> 
> The linespec parser doesn't normally require quoting:
> 
> Reading symbols from ~/tmp/file with spaces...done.
> (gdb) b file with spaces.c:3
> Breakpoint 1 at 0x4004fa: file /home/keiths/tmp/file with spaces.c, line 3.

OK, as long as

  b -source 'file with spaces -line 10' -line 20

works as expected (might be worth it of a test), the point is
moot then.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API
  2015-05-19 20:41     ` Keith Seitz
@ 2015-05-19 22:16       ` Pedro Alves
  0 siblings, 0 replies; 33+ messages in thread
From: Pedro Alves @ 2015-05-19 22:16 UTC (permalink / raw)
  To: Keith Seitz, Doug Evans; +Cc: gdb-patches

On 05/19/2015 09:41 PM, Keith Seitz wrote:
>> Note to self: Do we need both non-const and const versions?
>> [e.g., treat cached value as mutable in c++ sense?]
> 
> Yeah, if we could do something like that in C, that would negate the
> need for both versions. As it is, this seemed the easiest (and not
> an uncommon) way to deal with this. If you have another option, I'm all
> eyes.

You can cast away const for that.  See ada_decode_symbol for an example
of exactly that.  "const" in C does not mean that the object is set to
stone in read-only storage.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-19 22:15           ` Pedro Alves
@ 2015-05-19 22:20             ` Keith Seitz
  2015-05-21 19:34               ` [PATCH v5] Explicit locations: add UI features for CLI Keith Seitz
  2015-05-27  4:43               ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Doug Evans
  0 siblings, 2 replies; 33+ messages in thread
From: Keith Seitz @ 2015-05-19 22:20 UTC (permalink / raw)
  To: Pedro Alves, Doug Evans; +Cc: gdb-patches

On 05/19/2015 03:14 PM, Pedro Alves wrote:
> On 05/19/2015 11:12 PM, Keith Seitz wrote:
>> On 05/19/2015 03:09 PM, Pedro Alves wrote:
>>
> OK, as long as
> 
>   b -source 'file with spaces -line 10' -line 20
> 
> works as expected (might be worth it of a test), the point is
> moot then.

I think it does what is expected:

(gdb) b -source 'file with spaces -line 10' -line 20
No source file named file with spaces -line 10.

I'll add a test if one is missing. These "with spaces" tests appear in
ls-errs.exp and can be obscured by the fact that they test the parsing
by generating errors.

Keith

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v5] Explicit locations: add UI features for CLI
  2015-05-19 22:20             ` Keith Seitz
@ 2015-05-21 19:34               ` Keith Seitz
  2015-05-27  4:43               ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Doug Evans
  1 sibling, 0 replies; 33+ messages in thread
From: Keith Seitz @ 2015-05-21 19:34 UTC (permalink / raw)
  To: gdb-patches

This patch supersedes the previous submission.  While reviewing some
recent completer work, I ran across an instance where I should eat my
own dogfood [by using complete_on_enum where appropriate].

This patch was originally #7/9 (explicit-ui-cli).

Changes in this patch from v4:

1. Add comma-handling in explicit_location_lex_one.
2. Add tests for above.
3. if {0} completer tests that cause internal-error.
4. Change explicit_location_completer to use complete_on_enum.

--

This patch exposes explicit locations to the CLI user.  This enables
users to "explicitly" specify attributes of the breakpoint location
to avoid any ambiguity that might otherwise exist with linespecs.

The general syntax of explicit locations is:
-source SOURCE_FILENAME -line {+-}LINE -function FUNCTION_NAME
-label LABEL_NAME

Option names may be abbreviated, e.g., "-s SOURCE_FILENAME -li 3" and users
may use the completer with either options or values.

gdb/ChangeLog:

	* completer.c: Include location.h.
	(enum match_type): New enum.
	(location_completer): Rename to ...
	(linespec_completer): ... this.
	(collect_explicit_location_matches, backup_text_ptr)
	(explicit_location_completer): New functions.
	(location_completer): "New" function; handle linespec
	and explicit location completions.
	(complete_line_internal): Remove all location completer-specific
	handling.
	* linespec.c (linespec_lexer_lex_keyword, is_ada_operator)
	(find_toplevel_char): Export.
	(linespec_parse_line_offset): Export.
	Issue error if STRING is not numerical.
	(gdb_get_linespec_parser_quote_characters): New function.
	* linespec.h (linespec_parse_line_offset): Declare.
	(get_gdb_linespec_parser_quote_characters): Declare.
	(is_ada_operator): Declare.
	(find_toplevel_char): Declare.
	(linespec_lexer_lex_keyword): Declare.
	* location.c (explicit_to_event_location): New function.
	(explicit_location_lex_one): New function.
	(string_to_explicit_location): New function.
	(string_to_event_location): Handle explicit locations.
	* location.h (explicit_to_event_location): Declare.
	(string_to_explicit_location): Declare.

gdb/testsuite/ChangeLog:

	* gdb.linespec/3explicit.c: New file.
	* gdb.linespec/cpexplicit.cc: New file.
	* gdb.linespec/cpexplicit.exp: New file.
	* gdb.linespec/explicit.c: New file.
	* gdb.linespec/explicit.exp: New file.
	* gdb.linespec/explicit2.c: New file.
	* gdb.linespec/ls-errs.exp: Add explicit location tests.
---
 gdb/completer.c                           |  218 ++++++++++++++-
 gdb/linespec.c                            |   25 +-
 gdb/linespec.h                            |   20 +
 gdb/location.c                            |  218 +++++++++++++++
 gdb/location.h                            |   15 +
 gdb/testsuite/gdb.linespec/3explicit.c    |   28 ++
 gdb/testsuite/gdb.linespec/cpexplicit.cc  |   63 ++++
 gdb/testsuite/gdb.linespec/cpexplicit.exp |  112 ++++++++
 gdb/testsuite/gdb.linespec/explicit.c     |   56 ++++
 gdb/testsuite/gdb.linespec/explicit.exp   |  410 +++++++++++++++++++++++++++++
 gdb/testsuite/gdb.linespec/explicit2.c    |   24 ++
 gdb/testsuite/gdb.linespec/ls-errs.exp    |   45 +++
 12 files changed, 1195 insertions(+), 41 deletions(-)
 create mode 100644 gdb/testsuite/gdb.linespec/3explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpexplicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.c
 create mode 100644 gdb/testsuite/gdb.linespec/explicit.exp
 create mode 100644 gdb/testsuite/gdb.linespec/explicit2.c

diff --git a/gdb/completer.c b/gdb/completer.c
index c8c0e4c..38c57c0 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -26,6 +26,7 @@
 #include "target.h"
 #include "reggroups.h"
 #include "user-regs.h"
+#include "location.h"
 
 #include "cli/cli-decode.h"
 
@@ -42,6 +43,21 @@
 
 #include "completer.h"
 
+/* An enumeration of the various things a user might
+   attempt to complete for a location.  */
+
+enum explicit_location_match_type
+{
+    /* The filename of a source file.  */
+    MATCH_SOURCE,
+
+    /* The name of a function or method.  */
+    MATCH_FUNCTION,
+
+    /* The name of a label.  */
+    MATCH_LABEL
+};
+
 /* Prototypes for local functions.  */
 static
 char *line_completion_function (const char *text, int matches, 
@@ -174,7 +190,7 @@ filename_completer (struct cmd_list_element *ignore,
   return return_val;
 }
 
-/* Complete on locations, which might be of two possible forms:
+/* Complete on linespecs, which might be of two possible forms:
 
        file:line
    or
@@ -183,9 +199,9 @@ filename_completer (struct cmd_list_element *ignore,
    This is intended to be used in commands that set breakpoints
    etc.  */
 
-VEC (char_ptr) *
-location_completer (struct cmd_list_element *ignore, 
-		    const char *text, const char *word)
+static VEC (char_ptr) *
+linespec_location_completer (struct cmd_list_element *ignore,
+			     const char *text, const char *word)
 {
   int n_syms, n_files, ix;
   VEC (char_ptr) *fn_list = NULL;
@@ -332,6 +348,182 @@ location_completer (struct cmd_list_element *ignore,
   return list;
 }
 
+/* A helper function to collect explicit location matches for the given
+   LOCATION, which is attempting to match on WORD.  */
+
+static VEC (char_ptr) *
+collect_explicit_location_matches (struct event_location *location,
+				   enum explicit_location_match_type what,
+				   const char *word)
+{
+  VEC (char_ptr) *matches = NULL;
+  const struct explicit_location *explicit = get_explicit_location (location);
+
+  switch (what)
+    {
+    case MATCH_SOURCE:
+      {
+	const char *text = (explicit->source_filename == NULL
+			    ? "" : explicit->source_filename);
+
+	matches = make_source_files_completion_list (text, word);
+      }
+      break;
+
+    case MATCH_FUNCTION:
+      {
+	const char *text = (explicit->function_name == NULL
+			    ? "" : explicit->function_name);
+
+	if (explicit->source_filename != NULL)
+	  {
+	    matches
+	      = make_file_symbol_completion_list (text, word,
+						  explicit->source_filename);
+	  }
+	else
+	  matches = make_symbol_completion_list (text, word);
+      }
+      break;
+
+    case MATCH_LABEL:
+      /* Not supported.  */
+      break;
+
+    default:
+      gdb_assert_not_reached ("unhandled explicit_location_match_type");
+    }
+
+  return matches;
+}
+
+/* A convenience macro to (safely) back up P to the previous word.  */
+
+static const char *
+backup_text_ptr (const char *p, const char *text)
+{
+  while (p > text && isspace (*p))
+    --p;
+  for (; p > text && !isspace (p[-1]); --p)
+    ;
+
+  return p;
+}
+
+/* A completer function for explicit locations.  This function
+   completes both options ("-source", "-line", etc) and values.  */
+
+static VEC (char_ptr) *
+explicit_location_completer (struct cmd_list_element *ignore,
+			     struct event_location *location,
+			     const char *text, const char *word)
+{
+  const char *p;
+  VEC (char_ptr) *matches = NULL;
+
+  /* Find the beginning of the word.  This is necessary because
+     we need to know if we are completing an option name or value.  We
+     don't get the leading '-' from the completer.  */
+  p = backup_text_ptr (word, text);
+
+  if (*p == '-')
+    {
+      /* Completing on option name.  */
+      static const char *const keywords[] =
+	{
+	  "source",
+	  "function",
+	  "line",
+	  "label",
+	  NULL
+	};
+
+      /* Skip over the '-'.  */
+      ++p;
+
+      return complete_on_enum (keywords, p, p);
+    }
+  else
+    {
+      /* Completing on value (or unknown).  Get the previous word to see what
+	 the user is completing on.  */
+      size_t len, offset;
+      const char *new_word, *end;
+      enum explicit_location_match_type what;
+      struct explicit_location *explicit = get_explicit_location (location);
+
+      /* Backup P to the previous word, which should be the option
+	 the user is attempting to complete.  */
+      offset = word - p;
+      end = --p;
+      p = backup_text_ptr (p, text);
+      len = end - p;
+
+      if (strncmp (p, "-source", len) == 0)
+	{
+	  what = MATCH_SOURCE;
+	  new_word = explicit->source_filename + offset;
+	}
+      else if (strncmp (p, "-function", len) == 0)
+	{
+	  what = MATCH_FUNCTION;
+	  new_word = explicit->function_name + offset;
+	}
+      else if (strncmp (p, "-label", len) == 0)
+	{
+	  what = MATCH_LABEL;
+	  new_word = explicit->label_name + offset;
+	}
+      else
+	{
+	  /* The user isn't completing on any valid option name,
+	     e.g., "break -source foo.c [tab]".  */
+	  return NULL;
+	}
+
+      /* If the user hasn't entered a search expression, e.g.,
+	 "break -function <TAB><TAB>", new_word will be NULL, but
+	 search routines require non-NULL search words.  */
+      if (new_word == NULL)
+	new_word = "";
+
+      /* Now gather matches  */
+      matches = collect_explicit_location_matches (location, what, new_word);
+    }
+
+  return matches;
+}
+
+/* A completer for locations.  */
+
+VEC (char_ptr) *
+location_completer (struct cmd_list_element *ignore,
+		    const char *text, const char *word)
+{
+  VEC (char_ptr) *matches = NULL;
+  const char *copy = text;
+  struct event_location *location;
+
+  location = string_to_explicit_location (&copy, current_language, 1);
+  if (location != NULL)
+    {
+      struct cleanup *cleanup;
+
+      cleanup = make_cleanup_delete_event_location (location);
+      matches = explicit_location_completer (ignore, location, text, word);
+      do_cleanups (cleanup);
+    }
+  else
+    {
+      /* This is an address or linespec location.
+	 Right now both of these are handled by the (old) linespec
+	 completer.  */
+      matches = linespec_location_completer (ignore, text, word);
+    }
+
+  return matches;
+}
+
 /* Helper for expression_completer which recursively adds field and
    method names from TYPE, a struct or union type, to the array
    OUTPUT.  */
@@ -687,16 +879,6 @@ complete_line_internal (const char *text,
 		      rl_completer_word_break_characters =
 			gdb_completer_file_name_break_characters;
 		    }
-		  else if (c->completer == location_completer)
-		    {
-		      /* Commands which complete on locations want to
-			 see the entire argument.  */
-		      for (p = word;
-			   p > tmp_command
-			     && p[-1] != ' ' && p[-1] != '\t';
-			   p--)
-			;
-		    }
 		  if (reason == handle_brkchars
 		      && c->completer_handle_brkchars != NULL)
 		    (*c->completer_handle_brkchars) (c, p, word);
@@ -765,14 +947,6 @@ complete_line_internal (const char *text,
 		  rl_completer_word_break_characters =
 		    gdb_completer_file_name_break_characters;
 		}
-	      else if (c->completer == location_completer)
-		{
-		  for (p = word;
-		       p > tmp_command
-			 && p[-1] != ' ' && p[-1] != '\t';
-		       p--)
-		    ;
-		}
 	      if (reason == handle_brkchars
 		  && c->completer_handle_brkchars != NULL)
 		(*c->completer_handle_brkchars) (c, p, word);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 5e712e7..d2c5c53 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -323,8 +323,6 @@ static int compare_symbols (const void *a, const void *b);
 
 static int compare_msymbols (const void *a, const void *b);
 
-static const char *find_toplevel_char (const char *s, char c);
-
 /* Permitted quote characters for the parser.  This is different from the
    completer's quote characters to allow backward compatibility with the
    previous parser.  */
@@ -419,10 +417,9 @@ linespec_lexer_lex_keyword (const char *p)
   return NULL;
 }
 
-/* Does STRING represent an Ada operator?  If so, return the length
-   of the decoded operator name.  If not, return 0.  */
+/*  See description in linespec.h.  */
 
-static int
+int
 is_ada_operator (const char *string)
 {
   const struct ada_opname_map *mapping;
@@ -1140,7 +1137,7 @@ find_methods (struct type *t, const char *name,
    strings.  Also, ignore the char within a template name, like a ','
    within foo<int, int>.  */
 
-static const char *
+const char *
 find_toplevel_char (const char *s, char c)
 {
   int quoted = 0;		/* zero if we're not in quotes;
@@ -1551,11 +1548,12 @@ source_file_not_found_error (const char *name)
   throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
 }
 
-/* Parse and return a line offset in STRING.  */
+/* See description in linespec.h.  */
 
-static struct line_offset
+struct line_offset
 linespec_parse_line_offset (const char *string)
 {
+  const char *start = string;
   struct line_offset line_offset = {0, LINE_OFFSET_NONE};
 
   if (*string == '+')
@@ -1569,6 +1567,9 @@ linespec_parse_line_offset (const char *string)
       ++string;
     }
 
+  if (*string != '\0' && !isdigit (*string))
+    error (_("malformed line offset: \"%s\""), start);
+
   /* Right now, we only allow base 10 for offsets.  */
   line_offset.offset = atoi (string);
   return line_offset;
@@ -3883,3 +3884,11 @@ make_cleanup_destroy_linespec_result (struct linespec_result *ls)
 {
   return make_cleanup (cleanup_linespec_result, ls);
 }
+
+/* Return the quote characters permitted by the linespec parser.  */
+
+const char *
+get_gdb_linespec_parser_quote_characters (void)
+{
+  return linespec_quote_characters;
+}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 391ed26..2a76283 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -157,6 +157,26 @@ extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
 
 extern const char *linespec_lexer_lex_keyword (const char *p);
 
+/* Parse a line offset from STRING.  */
+
+extern struct line_offset linespec_parse_line_offset (const char *string);
+
+/* Return the quote characters permitted by the linespec parser.  */
+
+extern const char *get_gdb_linespec_parser_quote_characters (void);
+
+/* Does STRING represent an Ada operator?  If so, return the length
+   of the decoded operator name.  If not, return 0.  */
+
+extern int is_ada_operator (const char *string);
+
+/* Find an instance of the character C in the string S that is outside
+   of all parenthesis pairs, single-quoted strings, and double-quoted
+   strings.  Also, ignore the char within a template name, like a ','
+   within foo<int, int>.  */
+
+extern const char *find_toplevel_char (const char *s, char c);
+
 /* Find the end of the (first) linespec pointed to by *STRINGP.
    STRINGP will be advanced to this point.  */
 
diff --git a/gdb/location.c b/gdb/location.c
index 7882b2d..ea767db 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -442,6 +442,206 @@ event_location_to_string (struct event_location *location)
   return EL_STRING (location);
 }
 
+/* A lexer for explicit locations.  This function will advance INP
+   past any strings that it lexes.  Returns a malloc'd copy of the
+   lexed string or NULL if no lexing was done.  */
+
+static char *
+explicit_location_lex_one (const char **inp,
+			   const struct language_defn *language)
+{
+  const char *start = *inp;
+
+  if (*start == '\0')
+    return NULL;
+
+  /* If quoted, skip to the ending quote.  */
+  if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
+    {
+      char quote_char = *start;
+
+      /* If the input is not an Ada operator, skip to the matching
+	 closing quote and return the string.  */
+      if (!(language->la_language == language_ada
+	    && quote_char == '\"' && is_ada_operator (start)))
+	{
+	  const char *end = find_toplevel_char (start + 1, quote_char);
+
+	  if (end == NULL)
+	    error (_("Unmatched quote, %s."), start);
+	  *inp = end + 1;
+	  return savestring (start + 1, *inp - start - 2);
+	}
+    }
+
+  /* If the input starts with '-' or '+', the string ends with the next
+     whitespace or comma.  */
+  if (*start == '-' || *start == '+')
+    {
+      while (*inp[0] != '\0' && *inp[0] != ',' && !isspace (*inp[0]))
+	++(*inp);
+    }
+  else
+    {
+      /* Handle numbers first, stopping at the next whitespace or ','.  */
+      while (isdigit (*inp[0]))
+	++(*inp);
+      if (*inp[0] == '\0' || isspace (*inp[0]) || *inp[0] == ',')
+	return savestring (start, *inp - start);
+
+      /* Otherwise stop at the next occurrence of "SPACE -", '\0',
+	 keyword, or ','.  */
+      *inp = start;
+      while ((*inp)[0]
+	     && (*inp)[0] != ','
+	     && !(isspace ((*inp)[0])
+		  && ((*inp)[1] == '-'
+		      || linespec_lexer_lex_keyword (&(*inp)[1]))))
+	{
+	  /* Special case: C++ operator,.  */
+	  if (language->la_language == language_cplus
+	      && strncmp (*inp, "operator", 8)
+	      && (*inp)[9] == ',')
+	    (*inp) += 9;
+	  ++(*inp);
+	}
+    }
+
+  if (*inp - start > 0)
+    return savestring (start, *inp - start);
+
+  return NULL;
+}
+
+/* See description in location.h.  */
+
+struct event_location *
+string_to_explicit_location (const char **argp,
+			     const struct language_defn *language,
+			     int dont_throw)
+{
+  struct cleanup *cleanup;
+  struct event_location *location;
+
+  /* It is assumed that input beginning with '-' and a non-digit
+     character is an explicit location.  */
+  if (argp == NULL
+      || *argp == '\0'
+      || *argp[0] != '-'
+      || !isalpha ((*argp)[1]))
+    return NULL;
+
+  location = new_explicit_location (NULL);
+  cleanup = make_cleanup_delete_event_location (location);
+
+  /* Process option/argument pairs.  dprintf_command
+     requires that processing stop on ','.  */
+  while ((*argp)[0] != '\0' && (*argp)[0] != ',')
+    {
+      int len;
+      char *opt, *oarg;
+      const char *start;
+      struct cleanup *inner;
+
+      /* If *ARGP starts with a keyword, stop processing
+	 options.  */
+      if (linespec_lexer_lex_keyword (*argp) != NULL)
+	break;
+
+      /* Mark the start of the string in case we need to rewind.  */
+      start = *argp;
+
+      /* Get the option string.  */
+      opt = explicit_location_lex_one (argp, language);
+      inner = make_cleanup (xfree, opt);
+
+      *argp = skip_spaces_const (*argp);
+
+      /* Get the argument string.  */
+      oarg = explicit_location_lex_one (argp, language);
+
+      *argp = skip_spaces_const (*argp);
+
+      /* Use the length of the option to allow abbreviations.  */
+      len = strlen (opt);
+
+      /* All options have a required argument.  Checking for this required
+	 argument is deferred until later.  */
+      if (strncmp (opt, "-source", len) == 0)
+	EL_EXPLICIT (location)->source_filename = oarg;
+      else if (strncmp (opt, "-function", len) == 0)
+	EL_EXPLICIT (location)->function_name = oarg;
+      else if (strncmp (opt, "-line", len) == 0)
+	{
+	  if (oarg != NULL)
+	    {
+	      TRY
+		{
+		  EL_EXPLICIT (location)->line_offset
+		    = linespec_parse_line_offset (oarg);
+		}
+	      CATCH (e, RETURN_MASK_ERROR)
+		{
+		  xfree (oarg);
+		  throw_exception (e);
+		}
+	      END_CATCH
+	      xfree (oarg);
+	      do_cleanups (inner);
+	      continue;
+	    }
+	}
+      else if (strncmp (opt, "-label", len) == 0)
+	EL_EXPLICIT (location)->label_name = oarg;
+      /* Only emit an "invalid argument" error for options
+	 that look like option strings.  */
+      else if (opt[0] == '-' && !isdigit (opt[1]))
+	{
+	  xfree (oarg);
+	  if (!dont_throw)
+	    error (_("invalid explicit location argument, \"%s\""), opt);
+	}
+      else
+	{
+	  /* End of the explicit location specification.
+	     Stop parsing and return whatever explicit location was
+	     parsed.  */
+	  *argp = start;
+	  xfree (oarg);
+	  do_cleanups (inner);
+	  discard_cleanups (cleanup);
+	  return location;
+	}
+
+      /* It's a little lame to error after the fact, but in this
+	 case, it provides a much better user experience to issue
+	 the "invalid argument" error before any missing
+	 argument error.  */
+      if (oarg == NULL && !dont_throw)
+	error (_("missing argument for \"%s\""), opt);
+
+      /* The option/argument pair was successfully processed;
+	 oarg belongs to the explicit location, and opt should
+	 be freed.  */
+      do_cleanups (inner);
+    }
+
+  /* One special error check:  If a source filename was given
+     without offset, function, or label, issue an error.  */
+  if (EL_EXPLICIT (location)->source_filename != NULL
+      && EL_EXPLICIT (location)->function_name == NULL
+      && EL_EXPLICIT (location)->label_name == NULL
+      && (EL_EXPLICIT (location)->line_offset.sign == LINE_OFFSET_UNKNOWN)
+      && !dont_throw)
+    {
+      error (_("Source filename requires function, label, or "
+	       "line offset."));
+    }
+
+  discard_cleanups (cleanup);
+  return location;
+}
+
 /* See description in location.h.  */
 
 struct event_location *
@@ -474,8 +674,22 @@ string_to_event_location (char **stringp,
 	}
       else
 	{
-	  /* Everything else is a linespec.  */
-	  location = new_linespec_location (stringp);
+	  const char *arg, *orig;
+
+	  /* Next, try an explicit location.  */
+	  orig = arg = *stringp;
+	  location = string_to_explicit_location (&arg, language, 0);
+	  if (location != NULL)
+	    {
+	      /* It was a valid explicit location.  Advance STRINGP to
+		 the end of input.  */
+	      *stringp += arg - orig;
+	    }
+	  else
+	    {
+	      /* Everything else is a linespec.  */
+	      location = new_linespec_location (stringp);
+	    }
 	}
     }
 
diff --git a/gdb/location.h b/gdb/location.h
index 4e370bf..450b3a7 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -210,6 +210,21 @@ extern struct event_location *
   string_to_event_location (char **argp,
 			    const struct language_defn *langauge);
 
+/* Attempt to convert the input string in *ARGP into an explicit location.
+   ARGP is advanced past any processed input.  Returns an event_location
+   (malloc'd) if an explicit location was successfully found in *ARGP,
+   NULL otherwise.
+
+   IF !DONT_THROW, this function may call error() if *ARGP looks like
+   properly formed input, e.g., if it is called with missing argument
+   parameters or invalid options.  If DONT_THROW is non-zero, this function
+   will not throw any exceptions.  */
+
+extern struct event_location *
+  string_to_explicit_location (const char **argp,
+			       const struct language_defn *langauge,
+			       int dont_throw);
+
 /* A convenience function for testing for unset locations.  */
 
 extern int event_location_empty_p (const struct event_location *location);
diff --git a/gdb/testsuite/gdb.linespec/3explicit.c b/gdb/testsuite/gdb.linespec/3explicit.c
new file mode 100644
index 0000000..12bf277
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/3explicit.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static int
+myfunction4 (int arg)
+{
+  return arg + 2;
+}
+
+int
+myfunction3 (int arg)
+{
+  return myfunction4 (arg);
+}
diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.cc b/gdb/testsuite/gdb.linespec/cpexplicit.cc
new file mode 100644
index 0000000..42d50c7
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.cc
@@ -0,0 +1,63 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class myclass
+{
+public:
+  static int myfunction (int arg)  /* entry location */
+  {
+    int i, j, r;
+
+    j = 0; /* myfunction location */
+    r = arg;
+
+  top:
+    ++j;  /* top location */
+
+    if (j == 10)
+      goto done;
+
+    for (i = 0; i < 10; ++i)
+      {
+	r += i;
+	if (j % 2)
+	  goto top;
+      }
+
+  done:
+    return r;
+  }
+
+  int operator, (const myclass& c) { return 0; } /* operator location */
+};
+
+int
+main (void)
+{
+  int i, j;
+
+  /* Call the test function repeatedly, enough times for all our tests
+     without running forever if something goes wrong.  */
+  myclass c, d;
+  for (i = 0, j = 0; i < 1000; ++i)
+    {
+      j += myclass::myfunction (0);
+      j += (c,d);
+    }
+
+  return j;
+}
diff --git a/gdb/testsuite/gdb.linespec/cpexplicit.exp b/gdb/testsuite/gdb.linespec/cpexplicit.exp
new file mode 100644
index 0000000..90c8ce8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
@@ -0,0 +1,112 @@
+# Copyright 2012-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit linespecs
+
+if {[skip_cplus_tests]} {
+    unsupported "skipping C++ tests"
+    return
+}
+
+standard_testfile .cc
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile $srcfile \
+	 {c++ debug nowarnings}]} {
+    return -1
+}
+
+# Wrap this whole test in a namespace to avoid contaminating other tests.
+namespace eval $testfile {
+    # Test the given (explicit) LINESPEC which should cause gdb to break
+    # at LOCATION.
+    proc test_breakpoint {linespec location} {
+
+	# Delete all breakpoints, set a new breakpoint at LINESPEC,
+	# and attempt to run to it.
+	delete_breakpoints
+	gdb_breakpoint $linespec
+	gdb_continue_to_breakpoint $linespec $location
+    }
+
+    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+    # to stop at LOCATION.
+    proc add {thearray linespec location} {
+	upvar $thearray ar
+
+	lappend ar(linespecs) $linespec
+	lappend ar(locations) $location
+    }
+
+    # Some locations used in this test
+    variable lineno
+    variable location
+    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+    set lineno(entry) [gdb_get_line_number "entry location" $srcfile]
+    set lineno(top) [gdb_get_line_number "top location" $srcfile]
+    set lineno(operator) [gdb_get_line_number "operator location" $srcfile]
+    foreach v [array names lineno] {
+	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+    }
+
+    # A list of explicit linespecs and the corresponding location
+    variable linespecs
+    set linespecs(linespecs) {}
+    set linespecs(location) {}
+
+    add linespecs "-source $srcfile -function myclass::myfunction" \
+	$location(normal)
+    add linespecs "-source $srcfile -function myclass::myfunction -label top" \
+	$location(top)
+
+    # This isn't implemented yet; -line is silently ignored.
+    add linespecs \
+	"-source $srcfile -function myclass::myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+    add linespecs "-function myclass::myfunction" $location(normal)
+    add linespecs "-function myclass::myfunction -label top" $location(top)
+
+    # These are also not yet supported; -line is silently ignored.
+    add linespecs "-function myclass::myfunction -line 3" $location(normal)
+    add linespecs "-function myclass::myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-line 3" $location(normal)
+    add linespecs "-function myclass::operator," $location(operator)
+    add linespecs "-function 'myclass::operator,'" $location(operator)
+    add linespecs "-function \"myclass::operator,\"" $location(operator)
+
+    # Fire up gdb.
+    if {![runto_main]} {
+	namespace delete $testfile
+	return -1
+    }
+
+    # Test explicit linespecs, with and without conditions.
+    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+	# Test the linespec
+	test_breakpoint $linespec $loc_pattern
+    }
+
+    # Special (orphaned) dprintf cases.
+    gdb_test "dprintf -function myclass::operator,,\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+    gdb_test "dprintf -function 'myclass::operator,',\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+    gdb_test "dprintf -function \"myclass::operator,\",\"hello\"" \
+	"Dprintf .*$srcfile, line $lineno(operator)\\."
+}
+
+namespace delete $testfile
diff --git a/gdb/testsuite/gdb.linespec/explicit.c b/gdb/testsuite/gdb.linespec/explicit.c
new file mode 100644
index 0000000..4e1c635
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.c
@@ -0,0 +1,56 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction2 (int arg);
+
+static int
+myfunction (int arg)
+{
+  int i, j, r;
+
+  j = 0; /* myfunction location */
+  r = arg;
+
+ top:
+  ++j;  /* top location */
+
+  if (j == 10)
+    goto done;
+
+  for (i = 0; i < 10; ++i)
+    {
+      r += i;
+      if (j % 2)
+	goto top;
+    }
+
+ done:
+  return r;
+}
+
+int
+main (void)
+{
+  int i, j;
+
+  /* Call the test function repeatedly, enough times for all our tests
+     without running forever if something goes wrong.  */
+  for (i = 0, j = 0; i < 1000; ++i)
+    j += myfunction (0);
+
+  return myfunction2 (j);
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
new file mode 100644
index 0000000..414ec1c
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,410 @@
+# Copyright 2012-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit locations
+
+standard_testfile explicit.c explicit2.c 3explicit.c
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile \
+	 [list $srcfile $srcfile2 $srcfile3] {debug nowarnings}]} {
+    return -1
+}
+
+# Wrap the entire test in a namespace to avoid contaminating other tests.
+namespace eval $testfile {
+
+    # Test the given (explicit) LINESPEC which should cause gdb to break
+    # at LOCATION.
+    proc test_breakpoint {linespec location} {
+
+	set testname "set breakpoint at \"$linespec\""
+	# Delete all breakpoints, set a new breakpoint at LINESPEC,
+	# and attempt to run to it.
+	delete_breakpoints
+	if {[gdb_breakpoint $linespec]} {
+	    pass $testname
+	    send_log "\nexpecting locpattern \"$location\"\n"
+	    gdb_continue_to_breakpoint $linespec $location
+	} else {
+	    fail $testname
+	}
+    }
+
+    # Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+    # to stop at LOCATION.
+    proc add {thearray linespec location} {
+	upvar $thearray ar
+
+	lappend ar(linespecs) $linespec
+	lappend ar(locations) $location
+    }
+
+    # A list of all explicit linespec arguments.
+    variable all_arguments
+    set all_arguments {"source" "function" "label" "line"}
+
+    # Some locations used in this test
+    variable lineno
+    variable location
+    set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+    set lineno(top) [gdb_get_line_number "top location" $srcfile]
+    foreach v [array names lineno] {
+	set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+    }
+
+    # A list of explicit locations and the corresponding location.
+    variable linespecs
+    set linespecs(linespecs) {}
+    set linespecs(location) {}
+
+    add linespecs "-source $srcfile -function myfunction" $location(normal)
+    add linespecs "-source $srcfile -function myfunction -label top" \
+	$location(top)
+
+    # This isn't implemented yet; -line is silently ignored.
+    add linespecs "-source $srcfile -function myfunction -label top -line 3" \
+	$location(top)
+    add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+    add linespecs "-function myfunction" $location(normal)
+    add linespecs "-function myfunction -label top" $location(top)
+
+    # These are also not yet supported; -line is silently ignored.
+    add linespecs "-function myfunction -line 3" $location(normal)
+    add linespecs "-function myfunction -label top -line 3" $location(top)
+    add linespecs "-line 3" $location(normal)
+
+    # Test that static tracepoints on marker ID are not interpreted
+    # as an erroneous explicit option.
+    gdb_test "strace -m gdbfoobarbaz" "You can't do that.*"
+
+    # Fire up gdb.
+    if {![runto_main]} {
+	return -1
+    }
+
+    # Turn off queries
+    gdb_test_no_output "set confirm off"
+
+    # Simple error tests (many more are tested in ls-err.exp)
+    foreach arg $all_arguments {
+	# Test missing argument
+	gdb_test "break -$arg" \
+	    [string_to_regexp "missing argument for \"-$arg\""]
+
+	# Test abbreviations
+	set short [string range $arg 0 3]
+	gdb_test "break -$short" \
+	    [string_to_regexp "missing argument for \"-$short\""]
+    }
+
+    # Test invalid arguments
+    foreach arg {"-foo" "-foo bar" "-function myfunction -foo" \
+		     "-function -myfunction -foo bar"} {
+	gdb_test "break $arg" \
+	    [string_to_regexp "invalid explicit location argument, \"-foo\""]
+    }
+
+    # Test explicit locations, with and without conditions.
+    # For these tests, it is easiest to turn of pending breakpoint.
+    gdb_test_no_output "set breakpoint pending off" \
+	"turn off pending breakpoints"
+
+    foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+
+	# Test the linespec
+	test_breakpoint $linespec $loc_pattern
+
+	# Test with a valid condition
+	delete_breakpoints
+	set tst "set breakpoint at \"$linespec\" with valid condition"
+	if {[gdb_breakpoint "$linespec if arg == 0"]} {
+	    pass $tst
+
+	    gdb_test "info break" ".*stop only if arg == 0.*" \
+		"info break of conditional breakpoint at \"$linespec\""
+	} else {
+	    fail $tst
+	}
+
+	# Test with invalid condition
+	gdb_test "break $linespec if foofoofoo == 1" \
+	    ".*No symbol \"foofoofoo\" in current context.*" \
+	    "set breakpoint at \"$linespec\" with invalid condition"
+
+	# Test with thread
+	delete_breakpoints
+	gdb_test "break $linespec thread 123" "Unknown thread 123."
+    }
+
+    # Test the explicit location completer
+    foreach abbrev {"fun" "so" "lab" "li"}  full {"function" "source" "label" "line"} {
+	set tst "complete 'break -$abbrev'"
+	send_gdb "break -${abbrev}\t"
+	gdb_test_multiple "" $tst {
+	    "break -$full " {
+		send_gdb "\n"
+		gdb_test_multiple "" $tst {
+		    -re "missing argument for \"-$full\".*$gdb_prompt " {
+			pass $tst
+		    }
+		}
+	    }
+	}
+	set tst "complete -$full with no value"
+	send_gdb "break -$full \t"
+	gdb_test_multiple "" $tst {
+	    -re ".*break -$full " {
+		send_gdb "\n"
+		gdb_test_multiple "" $tst {
+		    -re ".*Source filename requires function, label, or line offset\..*$gdb_prompt " {
+			if {[string equal $full "source"]} {
+			    pass $tst
+			} else {
+			    faill $tst
+			}
+		    }
+		    -re "missing argument for \"-$full\".*$gdb_prompt " {
+			pass $tst
+		    }
+		}
+	    }
+	}
+    }
+
+    set tst "complete unique function name"
+    send_gdb "break -function mai\t"
+    gdb_test_multiple "" $tst {
+	"break -function mai\\\x07n" {
+	    send_gdb "\n"
+	    gdb_test "" ".*Breakpoint \[0-9\]+.*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+
+    set tst "complete non-unique function name"
+    send_gdb "break -function myfunc\t"
+    gdb_test_multiple "" $tst {
+	"break -function myfunc\\\x07tion" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nmyfunction\[ \t\]+myfunction2\[ \t\]+myfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
+		    gdb_test "2" ".*Breakpoint \[0-9\]+.*" $tst
+		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+		}
+	    }
+	}
+    }
+
+    set tst "complete non-existant function name"
+    send_gdb "break -function foo\t"
+    gdb_test_multiple "" $tst {
+	"break -function foo\\\x07" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" {Function "foo" not defined.} $tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete unique file name"
+    send_gdb "break -source 3ex\t"
+    gdb_test_multiple "" $tst {
+	"break -source 3explicit.c " {
+	    send_gdb "\n"
+	    gdb_test "" \
+		{Source filename requires function, label, or line offset.} $tst
+	}
+    }
+
+    set tst "complete non-unique file name"
+    send_gdb "break -source exp\t"
+    gdb_test_multiple "" $tst {
+	"break -source exp\\\x07licit" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+\r\n$gdb_prompt" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+
+	"break -source exp\\\x07l" {
+	    # This pattern may occur when glibc debuginfo is installed.
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+expl.*\r\n$gdb_prompt" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete non-existant file name"
+    send_gdb "break -source foo\t"
+    gdb_test_multiple "" $tst {
+	"break -source foo" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		"\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Source filename requires function, label, or line offset.} \
+			$tst
+		}
+	    }
+	}
+    }
+
+    # These tests are disabled pending resolution of gdb/17960.
+    # They cannot be XFAILed because they cause an internal-error.
+    if {0} {
+    set tst "complete filename and unique function name"
+    send_gdb "break -source explicit.c -function ma\t"
+    gdb_test_multiple "" $tst {
+	"break -source explicit.c -function main " {
+	    send_gdb "\n"
+	    gdb_test "" ".*Breakpoint .*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+
+    set tst "complete filename and non-unique function name"
+    send_gdb "break -so 3explicit.c -func myfunc\t"
+    gdb_test_multiple "" $tst {
+	"break -so 3explicit.c -func myfunc\\\x07tion" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		-re "\\\x07\r\nmyfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
+		    gdb_test "3" ".*Breakpoint \[0-9\]+.*" $tst
+		    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+		}
+	    }
+	}
+    }
+
+    set tst "complete filename and non-existant function name"
+    send_gdb "break -sou 3explicit.c -fun foo\t"
+    gdb_test_multiple "" $tst {
+	"break -sou 3explicit.c -fun foo\\\x07" {
+	    send_gdb "\t\t"
+	    gdb_test_multiple "" $tst {
+		"\\\x07\\\x07" {
+		    send_gdb "\n"
+		    gdb_test "" \
+			{Function "foo" not defined in "3explicit.c".} $tst
+		}
+	    }
+	}
+    }
+
+    set tst "complete filename and function reversed"
+    send_gdb "break -func myfunction4 -source 3ex\t"
+    gdb_test_multiple "" $tst {
+	"break -func myfunction4 -source 3explicit.c " {
+	    send_gdb "\n"
+	    gdb_test "" "Breakpoint \[0-9\]+.*" $tst
+	    gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	}
+    }
+    }
+
+    # NOTE: We don't bother testing more elaborate combinations of options,
+    # such as "-func main -sour 3ex\t" (main is defined in explicit.c).  The
+    # completer cannot handle these yet.
+
+    # Test pending explicit breakpoints
+    gdb_exit
+    gdb_start
+
+    set tst "pending invalid conditional explicit breakpoint"
+    if {![gdb_breakpoint "-func myfunction if foofoofoo == 1" \
+	      allow-pending]} {
+	fail "set $tst"
+    } else {
+	gdb_test "info break" ".*PENDING.*myfunction if foofoofoo == 1.*" $tst
+    }
+
+    gdb_exit
+    gdb_start
+
+    set tst "pending valid conditional explicit breakpoint"
+    if {![gdb_breakpoint "-func myfunction if arg == 0" \
+	      allow-pending]} {
+	fail "set $tst"
+    } else {
+	gdb_test "info break" ".*PENDING.*myfunction if arg == 0" $tst
+
+	gdb_load [standard_output_file $exefile]
+	gdb_test "info break" \
+	    ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" \
+	    "$tst resolved"
+    }
+
+    # Test interaction of condition command and explicit linespec conditons.
+    gdb_exit
+    gdb_start
+    gdb_load [standard_output_file $exefile]
+
+    set tst "condition_command overrides explicit linespec condition"
+    if {![runto main]} {
+	fail $tst
+    } else {
+	if {![gdb_breakpoint "-func myfunction if arg == 1"]} {
+	    fail "set breakpoint with condition 'arg == 1'"
+	} else {
+	    gdb_test_no_output "cond 2 arg == 0" \
+		"set new breakpoint condition for explicit linespec"
+
+	    gdb_continue_to_breakpoint $tst $location(normal)
+	}
+    }
+
+    gdb_test "cond 2" [string_to_regexp "Breakpoint 2 now unconditional."] \
+	"clear condition for explicit breakpoint"
+    set tst "info break of cleared condition of explicit breakpoint"
+    gdb_test_multiple "info break" $tst {
+	-re ".*in myfunction at .*$srcfile:.*stop only if arg == 0.*" {
+	    fail $tst
+	}
+	-re ".*in myfunction at .*$srcfile:.*$gdb_prompt $" {
+	    pass $tst
+	}
+    }
+
+    # Test explicit "ranges."  Make sure that using explicit
+    # locations doesn't alter the expected outcome.
+    gdb_test "list main" ".*" "list main 1"
+    set list_result [capture_command_output "list -,+" ""]
+    gdb_test "list main" ".*" "list main 2"
+    gdb_test "list -line -,-line +" [string_to_regexp $list_result]
+
+    # Ditto for the reverse (except that no output is expected).
+    gdb_test "list myfunction" ".*" "list myfunction 1"
+    gdb_test_no_output "list +,-"
+    gdb_test "list myfunction" ".*" "list myfunction 2"
+    gdb_test_no_output "list -line +, -line -"
+}
+
+namespace delete $testfile
diff --git a/gdb/testsuite/gdb.linespec/explicit2.c b/gdb/testsuite/gdb.linespec/explicit2.c
new file mode 100644
index 0000000..218cccb
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit2.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction3 (int arg);
+
+int
+myfunction2 (int arg)
+{
+  return myfunction3 (arg);
+}
diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp
index 019312c..c220241 100644
--- a/gdb/testsuite/gdb.linespec/ls-errs.exp
+++ b/gdb/testsuite/gdb.linespec/ls-errs.exp
@@ -49,11 +49,16 @@ array set error_messages {
     invalid_var_or_func_f \
 	"Undefined convenience variable or function \"%s\" not defined in \"%s\"."
     invalid_label "No label \"%s\" defined in function \"%s\"."
+    invalid_parm "invalid linespec argument, \"%s\""
     invalid_offset "No line %d in the current file."
     invalid_offset_f "No line %d in file \"%s\"."
+    malformed_line_offset "malformed line offset: \"%s\""
+    source_incomplete \
+	"Source filename requires function, label, or line offset."
     unexpected "malformed linespec error: unexpected %s"
     unexpected_opt "malformed linespec error: unexpected %s, \"%s\""
     unmatched_quote "unmatched quote"
+    garbage "Garbage '%s' at end of command"
 }
 
 # Some commonly used whitespace tests around ':'.
@@ -80,6 +85,7 @@ foreach x $invalid_offsets {
 	incr offset 16
     }
     test_break $x invalid_offset $offset
+    test_break "-line $x" invalid_offset $offset
 }
 
 # Test offsets with trailing tokens w/ and w/o spaces.
@@ -91,13 +97,17 @@ foreach x $spaces {
 
 foreach x {1 +1 +100 -10} {
     test_break "3 $x" unexpected_opt "number" $x
+    test_break "-line 3 $x" garbage $x
     test_break "+10 $x" unexpected_opt "number" $x
+    test_break "-line +10 $x" garbage $x
     test_break "-10 $x" unexpected_opt "number" $x
+    test_break "-line -10 $x" garbage $x
 }
 
-test_break "3 foo" unexpected_opt "string" "foo"
-test_break "+10 foo" unexpected_opt "string" "foo"
-test_break "-10 foo" unexpected_opt "string" "foo"
+foreach x {3 +10 -10} {
+    test_break "$x foo" unexpected_opt "string" "foo"
+    test_break "-line $x foo" garbage "foo"
+}
 
 # Test invalid linespecs starting with filename.
 foreach x [list "this_file_doesn't_exist.c" \
@@ -113,6 +123,13 @@ foreach x [list "this_file_doesn't_exist.c" \
     # Remove any quoting from FILENAME for the error message.
     test_break "$x:3" invalid_file [string trim $x \"']
 }
+foreach x [list "this_file_doesn't_exist.c" \
+	       "this file has spaces.c" \
+	       "file::colons.c" \
+	       "'file::colons.c'"] {
+    test_break "-source $x -line 3" \
+	invalid_file [string trim $x \"']
+}
 
 # Test unmatched quotes.
 foreach x {"\"src-file.c'" "'src-file.c"} {
@@ -123,7 +140,11 @@ test_break $srcfile invalid_function $srcfile
 foreach x {"foo" " foo" " foo "} {
     # Trim any leading/trailing whitespace for error messages.
     test_break "$srcfile:$x" invalid_function_f [string trim $x] $srcfile
+    test_break "-source $srcfile -function $x" \
+	invalid_function_f [string trim $x] $srcfile
     test_break "$srcfile:main:$x" invalid_label [string trim $x] "main"
+    test_break "-source $srcfile -function main -label $x" \
+	invalid_label [string trim $x] "main"
 }
 
 foreach x $spaces {
@@ -133,20 +154,26 @@ foreach x $spaces {
 
 test_break "${srcfile}::" invalid_function "${srcfile}::"
 test_break "$srcfile:3 1" unexpected_opt "number" "1"
+test_break "-source $srcfile -line 3 1" garbage "1"
 test_break "$srcfile:3 +100" unexpected_opt "number" "+100"
+test_break "-source $srcfile -line 3 +100" garbage "+100"
 test_break "$srcfile:3 -100" unexpected_opt "number" "-100"
 test_break "$srcfile:3 foo" unexpected_opt "string" "foo"
+test_break "-source $srcfile -line 3 foo" garbage "foo"
 
 foreach x $invalid_offsets {
     test_break "$srcfile:$x" invalid_offset_f $x $srcfile
     test_break "\"$srcfile:$x\"" invalid_offset_f $x $srcfile
     test_break "'$srcfile:$x'" invalid_offset_f $x $srcfile
+    test_break "-source $srcfile -line $x" invalid_offset_f $x $srcfile
 }
+test_break "-source $srcfile -line -x" malformed_line_offset "-x"
 
 # Test invalid filespecs starting with function.
 foreach x {"foobar" "foo::bar" "foo.bar" "foo ." "foo bar" "foo 1" \
 	       "foo 0" "foo +10" "foo -10" "foo +100" "foo -100"} {
     test_break $x invalid_function $x
+    test_break "-function \"$x\"" invalid_function $x
 }
 
 foreach x $spaces {
@@ -155,13 +182,12 @@ foreach x $spaces {
     test_break "main:here${x}" unexpected "end of input"
 }
 
-test_break "main 3" invalid_function "main 3"
-test_break "main +100" invalid_function "main +100"
-test_break "main -100" invalid_function "main -100"
-test_break "main foo" invalid_function "main foo"
-
 foreach x {"3" "+100" "-100" "foo"} {
+    test_break "main 3" invalid_function "main 3"
+    test_break "-function \"main $x\"" invalid_function "main $x"
     test_break "main:here $x" invalid_label "here $x" "main"
+    test_break "-function main -label \"here $x\"" \
+	invalid_label "here $x" "main"
 }
 
 foreach x {"if" "task" "thread"} {
@@ -178,3 +204,6 @@ test_break "'main.c'+3" unexpected_opt "number" "+3"
 set x {$zippo}
 test_break $x invalid_var_or_func $x
 test_break "$srcfile:$x" invalid_var_or_func_f $x $srcfile
+
+# Explicit linespec-specific tests
+test_break "-source $srcfile" source_incomplete

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 7/9] Explicit locations: add UI features for CLI
  2015-05-19 20:41     ` Keith Seitz
@ 2015-05-27  4:27       ` Doug Evans
  0 siblings, 0 replies; 33+ messages in thread
From: Doug Evans @ 2015-05-27  4:27 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
>>> +/* See description in location.h.  */
>>> +
>>> +struct event_location *
>>> +string_to_explicit_location (const char **argp,
>>> +			     const struct language_defn *language,
>>> +			     int dont_throw)
>>> +{
>>> +  struct cleanup *cleanup;
>>> +  struct event_location *location;
>>> +
>>> +  /* It is assumed that input beginning with '-' and a non-digit
>>> +     character is an explicit location.  */
>>> +  if (argp == NULL
>>> +      || *argp == '\0'
>>> +      || *argp[0] != '-'
>>> +      || !isalpha ((*argp)[1]))
>>> +    return NULL;
>>> +
>>> +  location = new_explicit_location (NULL);
>>> +  cleanup = make_cleanup_delete_event_location (location);
>>> +
>>> +  /* Process option/argument pairs.  dprintf_command
>>> +     requires that processing stop on ','.  */
>>> +  while ((*argp)[0] != '\0' && (*argp)[0] != ',')
>>> +    {
>>> +      int len;
>>> +      char *opt, *oarg;
>>> +      const char *start;
>>> +      struct cleanup *inner;
>>> +
>>> +      /* If *ARGP starts with a keyword, stop processing
>>> +	 options.  */
>>> +      if (linespec_lexer_lex_keyword (*argp) != NULL)
>>> +	break;
>>> +
>>> +      /* Mark the start of the string in case we need to rewind.  */
>>> +      start = *argp;
>>> +
>>> +      /* Get the option string.  */
>>> +      opt = explicit_location_lex_one (argp, language);
>>> +      inner = make_cleanup (xfree, opt);
>>> +
>>> +      *argp = skip_spaces_const (*argp);
>>> +
>>> +      /* Get the argument string.  */
>>> +      oarg = explicit_location_lex_one (argp, language);
>>> +
>>> +      *argp = skip_spaces_const (*argp);
>>> +
>>> +      /* Use the length of the option to allow abbreviations.  */
>>> +      len = strlen (opt);
>>> +
>>> +      /* All options have a required argument.  Checking for this required
>>> +	 argument is deferred until later.  */
>>> +      if (strncmp (opt, "-source", len) == 0)
>>> +	EL_EXPLICIT (location)->source_filename = oarg;
>>> +      else if (strncmp (opt, "-function", len) == 0)
>>> +	EL_EXPLICIT (location)->function_name = oarg;
>>> +      else if (strncmp (opt, "-line", len) == 0)
>>> +	{
>>> +	  if (oarg != NULL)
>>> +	    {
>>> +	      TRY
>>> +		{
>>> +		  EL_EXPLICIT (location)->line_offset
>>> +		    = linespec_parse_line_offset (oarg);
>>> +		}
>>> +	      CATCH (e, RETURN_MASK_ERROR)
>>> +		{
>>> +		  xfree (oarg);
>> 
>> Could other exception types leak oarg here?
>
> Not that I can see. When any successful argument value is parsed, it is
> added to the event_location, which has a cleanup on it which will free
> any defined members when an exception occurs.
>
> The only two functions (in this loop) that could throw an exception are
> explicit_location_lex_one and linespec_parse_line_offset.
>
> In the former case, the option name has a cleanup when parsing the
> value. The value is either saved into the event_location or discarded if
> we are going to throw an exception.
>
> linespec_parse_line_offset can throw an error (GENERIC_ERROR), but it is
> already caught and memory for oarg is freed. Nothing can generate a
> RETURN_QUIT as far as I can tell. Did you have a case specifically in mind?

I'm just worried about the robustness (or lack thereof)
to future changes.

Plus the readability.
You've done the research to conclude that the code is ok,
(e.g., linespec_parse_line_offset doesn't call QUIT)
but the casual reader will be left with the question:
"Hmmm, can oarg leak?", and a conscientious reader would then
have to put in the time to do that research too.
It'd be preferable if the code could be read and
understood to be correct without having to do that research.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-19 22:20             ` Keith Seitz
  2015-05-21 19:34               ` [PATCH v5] Explicit locations: add UI features for CLI Keith Seitz
@ 2015-05-27  4:43               ` Doug Evans
  2015-05-27 11:36                 ` Matt Rice
  1 sibling, 1 reply; 33+ messages in thread
From: Doug Evans @ 2015-05-27  4:43 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Pedro Alves, gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> On 05/19/2015 03:14 PM, Pedro Alves wrote:
>> On 05/19/2015 11:12 PM, Keith Seitz wrote:
>>> On 05/19/2015 03:09 PM, Pedro Alves wrote:
>>>
>> OK, as long as
>> 
>>   b -source 'file with spaces -line 10' -line 20
>> 
>> works as expected (might be worth it of a test), the point is
>> moot then.
>
> I think it does what is expected:
>
> (gdb) b -source 'file with spaces -line 10' -line 20
> No source file named file with spaces -line 10.

This error message needs to better delineate the file name.
One could either put it in quotes (and escape internal quotes),
or change it to something like:
No such source file: file with spaces -line 10.

> I'll add a test if one is missing. These "with spaces" tests appear in
> ls-errs.exp and can be obscured by the fact that they test the parsing
> by generating errors.

I'm still really uneasy with supporting
b -source file with spaces -line 20

This is intended to be the low-level access to specifying locations.
Low level APIs shouldn't be too concerned with easing typing.

It's easier to relax restrictions than impose them after the fact.
Can we require such files to be quoted today,
and then later relax the restriction if there's a compelling
reason to do so?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-27  4:43               ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Doug Evans
@ 2015-05-27 11:36                 ` Matt Rice
  2015-05-30 15:17                   ` Matt Rice
  0 siblings, 1 reply; 33+ messages in thread
From: Matt Rice @ 2015-05-27 11:36 UTC (permalink / raw)
  To: Doug Evans; +Cc: Keith Seitz, Pedro Alves, gdb-patches

On Tue, May 26, 2015 at 9:42 PM, Doug Evans <xdje42@gmail.com> wrote:
> Keith Seitz <keiths@redhat.com> writes:
>> On 05/19/2015 03:14 PM, Pedro Alves wrote:
>>> On 05/19/2015 11:12 PM, Keith Seitz wrote:
>>>> On 05/19/2015 03:09 PM, Pedro Alves wrote:
>>>>
>>> OK, as long as
>>>
>>>   b -source 'file with spaces -line 10' -line 20
>>>
>>> works as expected (might be worth it of a test), the point is
>>> moot then.
>>
>> I think it does what is expected:
>>
>> (gdb) b -source 'file with spaces -line 10' -line 20
>> No source file named file with spaces -line 10.
>
> This error message needs to better delineate the file name.
> One could either put it in quotes (and escape internal quotes),
> or change it to something like:
> No such source file: file with spaces -line 10.
>
>> I'll add a test if one is missing. These "with spaces" tests appear in
>> ls-errs.exp and can be obscured by the fact that they test the parsing
>> by generating errors.
>
> I'm still really uneasy with supporting
> b -source file with spaces -line 20
>
> This is intended to be the low-level access to specifying locations.
> Low level APIs shouldn't be too concerned with easing typing.

hmm, I just thought of a 2nd pitfall:
in objective-c "b -method" I believe is a currently working linespec
to set breakpoints on all the instance methods name 'method' that
accept zero arguments.

thus there is the potential for collisions, the following header[1]
file declares a method on line 47: - (id) source; which should
currently be accepted via the linespec: 'b -source'

[1] https://github.com/gnustep/gui/blob/master/Headers/AppKit/NSNibConnector.h

> It's easier to relax restrictions than impose them after the fact.
> Can we require such files to be quoted today,
> and then later relax the restriction if there's a compelling
> reason to do so?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v4 6/9] Explicit locations: introduce explicit locations
  2015-05-27 11:36                 ` Matt Rice
@ 2015-05-30 15:17                   ` Matt Rice
  0 siblings, 0 replies; 33+ messages in thread
From: Matt Rice @ 2015-05-30 15:17 UTC (permalink / raw)
  To: Doug Evans; +Cc: Keith Seitz, Pedro Alves, gdb-patches

On Wed, May 27, 2015 at 4:36 AM, Matt Rice <ratmice@gmail.com> wrote:
> On Tue, May 26, 2015 at 9:42 PM, Doug Evans <xdje42@gmail.com> wrote:
>> Keith Seitz <keiths@redhat.com> writes:
>>> On 05/19/2015 03:14 PM, Pedro Alves wrote:
>>>> On 05/19/2015 11:12 PM, Keith Seitz wrote:
>>>>> On 05/19/2015 03:09 PM, Pedro Alves wrote:
>>>>>
>>>> OK, as long as
>>>>
>>>>   b -source 'file with spaces -line 10' -line 20
>>>>
>>>> works as expected (might be worth it of a test), the point is
>>>> moot then.
>>>
>>> I think it does what is expected:
>>>
>>> (gdb) b -source 'file with spaces -line 10' -line 20
>>> No source file named file with spaces -line 10.
>>
>> This error message needs to better delineate the file name.
>> One could either put it in quotes (and escape internal quotes),
>> or change it to something like:
>> No such source file: file with spaces -line 10.
>>
>>> I'll add a test if one is missing. These "with spaces" tests appear in
>>> ls-errs.exp and can be obscured by the fact that they test the parsing
>>> by generating errors.
>>
>> I'm still really uneasy with supporting
>> b -source file with spaces -line 20
>>
>> This is intended to be the low-level access to specifying locations.
>> Low level APIs shouldn't be too concerned with easing typing.
>
> hmm, I just thought of a 2nd pitfall:
> in objective-c "b -method" I believe is a currently working linespec
> to set breakpoints on all the instance methods name 'method' that
> accept zero arguments.
>
> thus there is the potential for collisions, the following header[1]
> file declares a method on line 47: - (id) source; which should
> currently be accepted via the linespec: 'b -source'
>
> [1] https://github.com/gnustep/gui/blob/master/Headers/AppKit/NSNibConnector.h


It appears that my memory may be failing me:

with the file foo.m:

@interface Foo
 - (void) source;
 + (void) foo;
@end

@implementation
Foo
 - (void) source {};
 + (void) foo {};
@end

int main() {
 [Foo foo];
 return 0;
}

$ gcc -g foo.m -lobjc

Reading symbols from a.out...done.
(gdb) b foo
Breakpoint 1 at 0x40076a: file foo.m, line 10.
(gdb) b source
Breakpoint 2 at 0x40075c: file foo.m, line 9.
(gdb) b -source
Function "-source" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b -[Foo source]
Note: breakpoint 2 also set at pc 0x40075c.
Breakpoint 3 at 0x40075c: file foo.m, line 9.
(gdb) b +foo
Function "+foo" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b +[Foo foo]
Note: breakpoint 1 also set at pc 0x40076a.
Breakpoint 4 at 0x40076a: file foo.m, line 10.
(gdb)

So, this doesn't seem to work currently, and if it did work in the
past it was not reflected in the testsuite or the documentation
afaict.

so 'b foo' and 'b source', can specify breakpoints on class or instance methods,
but to specify a breakpoint on an instance method you must specify the
[] brackets, and the class as well, rather than being able to specify
a breakpoint on all instance methods or all class methods.

haven't tested older versions though to see if this is actually my
memory failing me, or just some undocumented feature which has stopped
working, sorry for the noise.

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2015-05-30 15:17 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-07 18:05 [PATCH v4 0/9] Locations API Keith Seitz
2015-05-07 18:05 ` [PATCH v4 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
2015-05-17 20:54   ` Doug Evans
2015-05-19 20:41     ` Keith Seitz
2015-05-19 22:16       ` Pedro Alves
2015-05-07 18:06 ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Keith Seitz
2015-05-18  6:13   ` Doug Evans
2015-05-18 20:14     ` Keith Seitz
2015-05-19 22:09       ` Pedro Alves
2015-05-19 22:12         ` Keith Seitz
2015-05-19 22:15           ` Pedro Alves
2015-05-19 22:20             ` Keith Seitz
2015-05-21 19:34               ` [PATCH v5] Explicit locations: add UI features for CLI Keith Seitz
2015-05-27  4:43               ` [PATCH v4 6/9] Explicit locations: introduce explicit locations Doug Evans
2015-05-27 11:36                 ` Matt Rice
2015-05-30 15:17                   ` Matt Rice
2015-05-07 18:06 ` [PATCH v4 8/9] Explicit locations: MI support for " Keith Seitz
2015-05-18  7:16   ` Doug Evans
2015-05-07 18:06 ` [PATCH v4 7/9] Explicit locations: add UI features for CLI Keith Seitz
2015-05-18  6:55   ` Doug Evans
2015-05-19 20:41     ` Keith Seitz
2015-05-27  4:27       ` Doug Evans
2015-05-07 18:06 ` [PATCH v4 5/9] Explicit locations: introduce probe locations Keith Seitz
2015-05-18  5:49   ` Doug Evans
2015-05-07 18:06 ` [PATCH v4 4/9] Explicit locations: introduce address locations Keith Seitz
2015-05-18  5:45   ` Doug Evans
2015-05-07 18:06 ` [PATCH v4 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
2015-05-17 20:10   ` Doug Evans
2015-05-07 18:06 ` [PATCH v4 3/9] Explicit locations: use new location API Keith Seitz
2015-05-18  5:21   ` Doug Evans
2015-05-19 21:30     ` Keith Seitz
2015-05-07 18:13 ` [PATCH v4 9/9] Explicit locations: documentation updates Keith Seitz
2015-05-07 18:55   ` Eli Zaretskii

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).