public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
  2015-02-17 22:06 ` [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
  2015-02-17 22:06 ` [PATCH v3 4/9] Explicit locations: introduce address locations Keith Seitz
@ 2015-02-17 22:06 ` Keith Seitz
  2015-03-01 20:14   ` Doug Evans
  2015-02-17 22:07 ` [PATCH v3 8/9] Explicit locations: MI support for explicit locations Keith Seitz
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:06 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  |   56 +++++++++++++
 gdb/linespec.h  |    4 +
 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 00fb2cd..665853b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -836,7 +836,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 \
@@ -922,7 +922,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 solib-pa64.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 \
@@ -1003,7 +1003,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 0d012b4..f2ae93b 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -2418,6 +2418,62 @@ 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 *p, *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.keyword_ok = 1;
+  orig = p = *stringp;
+  parser.lexer.stream = &p;
+
+  TRY_CATCH (e, RETURN_MASK_ERROR)
+    {
+      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, *orig;
+
+	      orig = arg = *stringp;
+	      (void) linespec_expression_to_pc (&arg);
+	      PARSER_STREAM (&parser) += arg - orig;
+	      break;
+	    }
+
+	  token = linespec_lexer_consume_token (&parser);
+
+	  /* Keywords are okay after the first token.  */
+	  parser.keyword_ok = 1;
+	}
+      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
+    }
+
+  *stringp += PARSER_STREAM (&parser) - orig;
+  do_cleanups (cleanup);
+}
+
 /* See linespec.h.  */
 
 void
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 5520afa..728b1bd 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -152,4 +152,8 @@ extern struct symtabs_and_lines decode_line_with_current_source (char *, int);
 
 extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
 
+/* 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] 25+ messages in thread

* [PATCH v3 4/9] Explicit locations: introduce address locations
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
  2015-02-17 22:06 ` [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
@ 2015-02-17 22:06 ` Keith Seitz
  2015-03-01 21:03   ` Doug Evans
  2015-02-17 22:06 ` [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22: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                   |  195 ++++++++++++++++----------------------
 gdb/linespec.h                   |    5 +
 gdb/location.c                   |   61 ++++++++++++
 gdb/location.h                   |   17 +++
 gdb/python/py-finishbreakpoint.c |    8 --
 gdb/spu-tdep.c                   |    4 -
 7 files changed, 166 insertions(+), 142 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 5c3be10..ec0c6f8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7629,19 +7629,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);
 
@@ -9614,16 +9609,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 29e32e3..9c36d6c 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -316,7 +316,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,
@@ -1768,79 +1768,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.  */
@@ -1994,6 +1984,27 @@ 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);
+
+  if (self->canonical != NULL)
+    self->canonical->location = new_address_location (address);
+
+  return sals;
+}
+
 /* Create and return SALs from the linespec LS.  */
 
 static struct symtabs_and_lines
@@ -2001,18 +2012,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;
@@ -2110,8 +2110,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
@@ -2207,33 +2206,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;
 
@@ -2457,20 +2430,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, *orig;
-
-	      orig = arg = *stringp;
-	      (void) linespec_expression_to_pc (&arg);
-	      PARSER_STREAM (&parser) += arg - orig;
-	      break;
-	    }
-
 	  token = linespec_lexer_consume_token (&parser);
 
 	  /* Keywords are okay after the first token.  */
@@ -2508,6 +2467,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");
     }
@@ -2693,7 +2658,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 5f5bc71..8055f55 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);
    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 bbb408a..d145dfa 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -166,9 +166,8 @@ 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;
+  CORE_ADDR pc;
   volatile struct gdb_exception except;
-  char small_buf[100], *p;
   struct symbol *function;
 
   if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
@@ -291,10 +290,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 86af2ae..61dc98d 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -1957,7 +1957,6 @@ spu_catch_start (struct objfile *objfile)
   CORE_ADDR pc;
   struct event_location *location;
   struct cleanup *back_to;
-  char *p;
 
   /* Do this only if requested by "set spu stop-on-load on".  */
   if (!spu_stop_on_load_p)
@@ -2001,8 +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.  */
-  p = ASTRDUP (core_addr_to_string (pc));
-  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] 25+ messages in thread

* [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location"
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
@ 2015-02-17 22:06 ` Keith Seitz
  2015-03-01 20:08   ` Doug Evans
  2015-02-17 22:06 ` [PATCH v3 4/9] Explicit locations: introduce address locations Keith Seitz
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22: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 fb04932..954e98b 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -225,7 +225,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);
 	}
 
       /* NOT_FOUND_ERROR just means the breakpoint will be pending, so
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2804453..c7d6c98 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -109,10 +109,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 *,
@@ -122,7 +122,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);
@@ -9992,8 +9992,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
   TRY_CATCH (e, RETURN_MASK_ALL)
     {
-      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);
     }
 
   /* If caller is interested in rc value from parse, set value.  */
@@ -13189,11 +13189,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 ();
 }
@@ -13215,7 +13215,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 ();
@@ -13253,9 +13253,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,
 };
@@ -13425,12 +13425,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);
 }
 
@@ -13456,10 +13456,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.  */
@@ -13659,10 +13659,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;
 
@@ -13675,7 +13675,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);
@@ -13768,12 +13768,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);
 }
 
@@ -13799,10 +13799,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;
@@ -13811,22 +13811,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;
@@ -13912,10 +13912,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;
 
@@ -13988,7 +13988,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;
@@ -14533,7 +14533,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};
@@ -14544,7 +14544,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
 
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {
-      b->ops->decode_linespec (b, &s, &sals);
+      b->ops->decode_location (b, &s, &sals);
     }
   if (e.reason < 0)
     {
@@ -14622,7 +14622,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);
@@ -14631,7 +14631,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);
@@ -14646,7 +14646,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)
@@ -14679,10 +14679,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;
@@ -16130,9 +16130,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;
@@ -16180,8 +16180,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;
@@ -16219,22 +16219,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 100d4f2..42c7427 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -554,14 +554,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
@@ -577,12 +577,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] 25+ messages in thread

* [PATCH v3 0/9] Locations API
@ 2015-02-17 22:06 Keith Seitz
  2015-02-17 22:06 ` [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
                   ` (9 more replies)
  0 siblings, 10 replies; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:06 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. The most important change in this
revision is the removal of some previous ugliness introduced by the
patch set to deal with advancing the input pointer for the CLI.

In this version, all of this has been removed (even from decode_line*).
This is now done (easily) by adding a new lexing function to find the
end of the linespec.

Thus, string_to_event_location can now treat all location types the same
and advance the input pointer past the first terminated location string.

General API usage now looks like:

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);
}

One note on this series... explicit-ui-cli will introduce a failing
test because of gdb/17960 (internal-error when completing "source.c:func").
This is trivially fixable after that patch has been committed.

I figure there's no harm in delaying further review. There's still quite
a way to go.


---

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                   |   20 +
 gdb/breakpoint.c                          |  773 +++++++++++++++++------------
 gdb/breakpoint.h                          |   30 +
 gdb/cli/cli-cmds.c                        |   47 +-
 gdb/completer.c                           |  211 +++++++-
 gdb/doc/gdb.texinfo                       |  234 ++++++---
 gdb/elfread.c                             |    4 
 gdb/linespec.c                            |  605 ++++++++++++++---------
 gdb/linespec.h                            |   51 ++
 gdb/location.c                            |  733 +++++++++++++++++++++++++++
 gdb/location.h                            |  238 +++++++++
 gdb/mi/mi-cmd-break.c                     |   76 +++
 gdb/probe.c                               |   21 +
 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 |  104 ++++
 gdb/testsuite/gdb.linespec/explicit.c     |   56 ++
 gdb/testsuite/gdb.linespec/explicit.exp   |  366 ++++++++++++++
 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 
 35 files changed, 3192 insertions(+), 766 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

--
Signature

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

* [PATCH v3 5/9] Explicit locations: introduce probe locations
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (4 preceding siblings ...)
  2015-02-17 22:07 ` [PATCH v3 6/9] Explicit locations: introduce " Keith Seitz
@ 2015-02-17 22:07 ` Keith Seitz
  2015-03-01 21:03   ` Doug Evans
  2015-02-17 22:07 ` [PATCH v3 7/9] Explicit locations: add UI features for CLI Keith Seitz
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:07 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 551f722..1803041 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -208,11 +208,10 @@ re_set_exception_catchpoint (struct breakpoint *self)
   struct cleanup *cleanup;
   enum exception_event_kind kind = classify_exception_breakpoint (self);
   struct event_location *location;
-  char *p;
 
   /* We first try to use the probe interface.  */
-  p = ASTRDUP (exception_functions[kind].probe);
-  location = new_linespec_location (&p);
+  location
+    = new_probe_location (exception_functions[kind].probe);
   cleanup = make_cleanup_delete_event_location (location);
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ec0c6f8..29c55e7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3496,7 +3496,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,
@@ -3511,8 +3510,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;
 	    }
 
@@ -3674,15 +3673,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;
 	    }
 
@@ -10262,7 +10260,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;
 
@@ -10270,7 +10267,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;
@@ -15534,11 +15532,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 9c36d6c..5f63750 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -2473,6 +2473,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 61236ee..1798286 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -57,7 +57,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);
@@ -176,7 +177,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] 25+ messages in thread

* [PATCH v3 6/9] Explicit locations: introduce explicit locations
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (3 preceding siblings ...)
  2015-02-17 22:07 ` [PATCH v3 8/9] Explicit locations: MI support for explicit locations Keith Seitz
@ 2015-02-17 22:07 ` Keith Seitz
  2015-03-01 21:04   ` Doug Evans
  2015-02-17 22:07 ` [PATCH v3 5/9] Explicit locations: introduce probe locations Keith Seitz
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:07 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 |    6 +
 gdb/breakpoint.c        |   43 ++++---
 gdb/linespec.c          |  303 ++++++++++++++++++++++++++---------------------
 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 1803041..902746f 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -222,11 +222,13 @@ re_set_exception_catchpoint (struct breakpoint *self)
   if (e.reason < 0)
     {
       volatile struct gdb_exception ex;
-      char *func = ASTRDUP (exception_functions[kind].function);
+      struct explicit_location explicit;
 
       /* Using the probe interface failed.  Let's fallback to the normal
 	 catchpoint mode.  */
-      location = new_linespec_location (&func);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (exception_functions[kind].function);
+      location = new_explicit_location (&explicit);
       cleanup = make_cleanup_delete_event_location (location);
       TRY_CATCH (ex, RETURN_MASK_ERROR)
 	{
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 29c55e7..046219b 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3403,7 +3403,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);
 
@@ -3428,8 +3428,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)
         {
@@ -3526,7 +3527,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;
@@ -3549,8 +3550,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;
 	}
     }
@@ -3581,7 +3583,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);
 
@@ -3607,8 +3609,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;
     }
   }
@@ -3632,7 +3635,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);
 
@@ -3713,8 +3716,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;
     }
 
@@ -14414,12 +14418,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);
 
@@ -14461,12 +14464,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 5f63750..10ef7f9 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
@@ -306,6 +258,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,
@@ -1551,6 +1507,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
@@ -1597,7 +1576,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.  */
@@ -1634,7 +1613,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);
     }
@@ -1648,7 +1627,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);
 	}
@@ -1656,14 +1635,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;
 	    }
@@ -1678,7 +1657,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;
 	}
@@ -1698,7 +1677,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);
 
@@ -1718,16 +1697,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.  */
@@ -1745,7 +1723,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);
 
@@ -1762,43 +1740,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;
 
@@ -1807,30 +1770,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.  */
@@ -1870,18 +1820,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;
@@ -1973,9 +1923,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);
@@ -2075,13 +2025,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);
 
@@ -2089,7 +2039,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
@@ -2106,6 +2056,73 @@ 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)
+    {
+      volatile struct gdb_exception except;
+
+      TRY_CATCH (except, RETURN_MASK_ERROR)
+	{
+	  result->file_symtabs
+	    = symtabs_from_filename (explicit->source_filename);
+	}
+
+      if (except.reason < 0 || result->file_symtabs == NULL)
+	source_file_not_found_error (explicit->source_filename);
+
+      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:
@@ -2216,13 +2233,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);
@@ -2258,7 +2275,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);
@@ -2295,7 +2312,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
@@ -2304,8 +2321,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:
@@ -2343,6 +2360,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.  */
@@ -2357,7 +2375,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);
 }
@@ -2377,10 +2395,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);
@@ -2457,6 +2474,7 @@ event_location_to_sals (linespec_parser *parser,
       {
 	volatile struct gdb_exception except;
 
+	PARSER_STATE (parser)->is_linespec = 1;
 	TRY_CATCH (except, RETURN_MASK_ERROR)
 	  {
 	    result = parse_linespec (parser, get_linespec_location (location));
@@ -2473,6 +2491,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");
@@ -2722,7 +2751,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);
@@ -2733,10 +2762,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);
@@ -3116,7 +3145,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] 25+ messages in thread

* [PATCH v3 7/9] Explicit locations: add UI features for CLI
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (5 preceding siblings ...)
  2015-02-17 22:07 ` [PATCH v3 5/9] Explicit locations: introduce probe locations Keith Seitz
@ 2015-02-17 22:07 ` Keith Seitz
  2015-03-01 21:14   ` Doug Evans
  2015-02-17 22:07 ` [PATCH v3 3/9] Explicit locations: use new location API Keith Seitz
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:07 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.
	(location_completer): 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                           |  211 +++++++++++++++--
 gdb/linespec.c                            |   30 ++
 gdb/linespec.h                            |   30 ++
 gdb/location.c                            |  214 +++++++++++++++++
 gdb/location.h                            |   15 +
 gdb/testsuite/gdb.linespec/3explicit.c    |   28 ++
 gdb/testsuite/gdb.linespec/cpexplicit.cc  |   63 +++++
 gdb/testsuite/gdb.linespec/cpexplicit.exp |  104 ++++++++
 gdb/testsuite/gdb.linespec/explicit.c     |   56 ++++
 gdb/testsuite/gdb.linespec/explicit.exp   |  366 +++++++++++++++++++++++++++++
 gdb/testsuite/gdb.linespec/explicit2.c    |   24 ++
 gdb/testsuite/gdb.linespec/ls-errs.exp    |   45 +++-
 12 files changed, 1143 insertions(+), 43 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 bfd2788..ec4ff17 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,175 @@ 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;
+}
+
+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;
+	}
+
+      /* 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.  */
@@ -684,16 +869,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);
@@ -762,14 +937,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 10ef7f9..c0ea3d9 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -327,8 +327,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.  */
@@ -375,10 +373,9 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
   return 1;
 }
 
-/* Does P represent one of the keywords?  If so, return
-   the keyword.  If not, return NULL.  */
+/* See description in linespec.h.  */
 
-static const char *
+const char *
 linespec_lexer_lex_keyword (const char *p)
 {
   int i;
@@ -400,10 +397,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;
@@ -1119,7 +1115,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;
@@ -1530,11 +1526,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 == '+')
@@ -1548,6 +1545,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;
@@ -3875,3 +3875,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 8055f55..6add0a7 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -152,6 +152,36 @@ extern struct symtabs_and_lines decode_line_with_current_source (char *, int);
 
 extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
 
+/* Parse a line offset from STRING.  */
+
+extern struct line_offset linespec_parse_line_offset (const char *string);
+
+/* A completion handler for locations.  */
+
+VEC (char_ptr) *location_completer (struct cmd_list_element *ignore,
+				    const char *text, const char *word);
+
+/* Return the quote characters permitted by the linespec parser.  */
+
+extern const char *get_gdb_linespec_parser_quote_characters (void);
+
+/* Does STRING represent an Ada operator?  If so, return the length
+   of the decoded operator name.  If not, return 0.  */
+
+extern int is_ada_operator (const char *string);
+
+/* Find an instance of the character C in the string S that is outside
+   of all parenthesis pairs, single-quoted strings, and double-quoted
+   strings.  Also, ignore the char within a template name, like a ','
+   within foo<int, int>.  */
+
+extern const char *find_toplevel_char (const char *s, char c);
+
+/* Does P represent one of the keywords?  If so, return
+   the keyword.  If not, return NULL.  */
+
+extern const char *linespec_lexer_lex_keyword (const char *p);
+
 /* 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..4e8c3b5 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -442,6 +442,202 @@ 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)
+	    {
+	      volatile struct gdb_exception e;
+
+	      TRY_CATCH (e, RETURN_MASK_ERROR)
+		{
+		  EL_EXPLICIT (location)->line_offset
+		    = linespec_parse_line_offset (oarg);
+		}
+
+	      xfree (oarg);
+	      if (e.reason < 0 && !dont_throw)
+		throw_exception (e);
+	      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 +670,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..2bb9291
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
@@ -0,0 +1,104 @@
+# Copyright 2012-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit linespecs
+
+if {[skip_cplus_tests]} {
+    unsupported "skipping C++ tests"
+    return
+}
+
+standard_testfile .cc
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile $srcfile \
+	 {c++ debug nowarnings}]} {
+    return -1
+}
+
+# Test the given (explicit) LINESPEC which should cause gdb to break
+# at LOCATION.
+proc test_breakpoint {linespec location} {
+
+    # Delete all breakpoints, set a new breakpoint at LINESPEC,
+    # and attempt to run to it.
+    delete_breakpoints
+    gdb_breakpoint $linespec
+    gdb_continue_to_breakpoint $linespec $location
+}
+
+# Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+# to stop at LOCATION.
+proc add {thearray linespec location} {
+    upvar $thearray ar
+
+    lappend ar(linespecs) $linespec
+    lappend ar(locations) $location
+}
+
+# Make sure variables are not already in use
+unset -nocomplain lineno location linespecs
+
+# Some locations used in this test
+set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+set lineno(entry) [gdb_get_line_number "entry location" $srcfile]
+set lineno(top) [gdb_get_line_number "top location" $srcfile]
+set lineno(operator) [gdb_get_line_number "operator location" $srcfile]
+foreach v [array names lineno] {
+    set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+}
+
+# A list of explicit linespecs and the corresponding location
+set linespecs(linespecs) {}
+set linespecs(location) {}
+
+add linespecs "-source $srcfile -function myclass::myfunction" $location(normal)
+add linespecs "-source $srcfile -function myclass::myfunction -label top" \
+    $location(top)
+
+# This isn't implemented yet; -line is silently ignored.
+add linespecs \
+    "-source $srcfile -function myclass::myfunction -label top -line 3" \
+    $location(top)
+add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+add linespecs "-function myclass::myfunction" $location(normal)
+add linespecs "-function myclass::myfunction -label top" $location(top)
+
+# These are also not yet supported; -line is silently ignored.
+add linespecs "-function myclass::myfunction -line 3" $location(normal)
+add linespecs "-function myclass::myfunction -label top -line 3" $location(top)
+add linespecs "-line 3" $location(normal)
+add linespecs "-function myclass::operator," $location(operator)
+add linespecs "-function 'myclass::operator,'" $location(operator)
+add linespecs "-function \"myclass::operator,\"" $location(operator)
+
+# Fire up gdb.
+if {![runto_main]} {
+    return -1
+}
+
+# Test explicit linespecs, with and without conditions.
+foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+    # Test the linespec
+    test_breakpoint $linespec $loc_pattern
+}
+
+# Special (orphaned) dprintf cases.
+gdb_test "dprintf -function myclass::operator,,\"hello\"" \
+    "Dprintf .*$srcfile, line $lineno(operator)\\."
+gdb_test "dprintf -function 'myclass::operator,',\"hello\"" \
+    "Dprintf .*$srcfile, line $lineno(operator)\\."
+gdb_test "dprintf -function \"myclass::operator,\",\"hello\"" \
+    "Dprintf .*$srcfile, line $lineno(operator)\\."
diff --git a/gdb/testsuite/gdb.linespec/explicit.c b/gdb/testsuite/gdb.linespec/explicit.c
new file mode 100644
index 0000000..4e1c635
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.c
@@ -0,0 +1,56 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction2 (int arg);
+
+static int
+myfunction (int arg)
+{
+  int i, j, r;
+
+  j = 0; /* myfunction location */
+  r = arg;
+
+ top:
+  ++j;  /* top location */
+
+  if (j == 10)
+    goto done;
+
+  for (i = 0; i < 10; ++i)
+    {
+      r += i;
+      if (j % 2)
+	goto top;
+    }
+
+ done:
+  return r;
+}
+
+int
+main (void)
+{
+  int i, j;
+
+  /* Call the test function repeatedly, enough times for all our tests
+     without running forever if something goes wrong.  */
+  for (i = 0, j = 0; i < 1000; ++i)
+    j += myfunction (0);
+
+  return myfunction2 (j);
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
new file mode 100644
index 0000000..854e16f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -0,0 +1,366 @@
+# Copyright 2012-2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Tests for explicit locations
+
+standard_testfile explicit.c explicit2.c 3explicit.c
+set exefile $testfile
+
+if {[prepare_for_testing $testfile $exefile \
+	 [list $srcfile $srcfile2 $srcfile3] {debug nowarnings}]} {
+    return -1
+}
+
+# Test the given (explicit) LINESPEC which should cause gdb to break
+# at LOCATION.
+proc test_breakpoint {linespec location} {
+
+    set testname "set breakpoint at \"$linespec\""
+    # Delete all breakpoints, set a new breakpoint at LINESPEC,
+    # and attempt to run to it.
+    delete_breakpoints
+    if {[gdb_breakpoint $linespec]} {
+	pass $testname
+	send_log "\nexpecting locpattern \"$location\"\n"
+	gdb_continue_to_breakpoint $linespec $location
+    } else {
+	fail $testname
+    }
+}
+
+# Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
+# to stop at LOCATION.
+proc add {thearray linespec location} {
+    upvar $thearray ar
+
+    lappend ar(linespecs) $linespec
+    lappend ar(locations) $location
+}
+
+# Make sure variables are not already in use
+unset -nocomplain all_arguments lineno location linespecs
+
+# A list of all explicit linespec arguments.
+set all_arguments {"source" "function" "label" "line"}
+
+# Some locations used in this test
+set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
+set lineno(top) [gdb_get_line_number "top location" $srcfile]
+foreach v [array names lineno] {
+    set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
+}
+
+# A list of explicit locations and the corresponding location.
+set linespecs(linespecs) {}
+set linespecs(location) {}
+
+add linespecs "-source $srcfile -function myfunction" $location(normal)
+add linespecs "-source $srcfile -function myfunction -label top" \
+    $location(top)
+
+# This isn't implemented yet; -line is silently ignored.
+add linespecs "-source $srcfile -function myfunction -label top -line 3" \
+    $location(top)
+add linespecs "-source $srcfile -line $lineno(top)" $location(top)
+add linespecs "-function myfunction" $location(normal)
+add linespecs "-function myfunction -label top" $location(top)
+
+# These are also not yet supported; -line is silently ignored.
+add linespecs "-function myfunction -line 3" $location(normal)
+add linespecs "-function myfunction -label top -line 3" $location(top)
+add linespecs "-line 3" $location(normal)
+
+# Test that static tracepoints on marker ID are not interpreted
+# as an erroneous explicit option.
+gdb_test "strace -m gdbfoobarbaz" "You can't do that.*"
+
+# Fire up gdb.
+if {![runto_main]} {
+    return -1
+}
+
+# Simple error tests (many more are tested in ls-err.exp)
+foreach arg $all_arguments {
+    # Test missing argument
+    gdb_test "break -$arg" [string_to_regexp "missing argument for \"-$arg\""]
+
+    # Test abbreviations
+    set short [string range $arg 0 3]
+    gdb_test "break -$short" \
+	[string_to_regexp "missing argument for \"-$short\""]
+}
+
+# Test invalid arguments
+foreach arg {"-foo" "-foo bar" "-function myfunction -foo" \
+		 "-function -myfunction -foo bar"} {
+    gdb_test "break $arg" \
+	[string_to_regexp "invalid explicit location argument, \"-foo\""]
+}
+
+# Test explicit locations, with and without conditions.
+# For these tests, it is easiest to turn of pending breakpoint.
+gdb_test_no_output "set breakpoint pending off" "turn off pending breakpoints"
+
+foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
+
+    # Test the linespec
+    test_breakpoint $linespec $loc_pattern
+
+    # Test with a valid condition
+    delete_breakpoints
+    set tst "set breakpoint at \"$linespec\" with valid condition"
+    if {[gdb_breakpoint "$linespec if arg == 0"]} {
+	pass $tst
+
+	gdb_test "info break" ".*stop only if arg == 0.*" \
+	    "info break of conditional breakpoint at \"$linespec\""
+    } else {
+	fail $tst
+    }
+
+    # Test with invalid condition
+    gdb_test "break $linespec if foofoofoo == 1" \
+	".*No symbol \"foofoofoo\" in current context.*" \
+	"set breakpoint at \"$linespec\" with invalid condition"
+
+    # Test with thread
+    delete_breakpoints
+    gdb_test "break $linespec thread 123" "Unknown thread 123."
+}
+
+# Test the explicit location completer
+foreach abbrev {"fun" "so" "lab" "li"} \
+    full {"function" "source" "label" "line"} {
+    set tst "complete 'break -$abbrev'"
+    send_gdb "break -${abbrev}\t"
+    gdb_test_multiple "" $tst {
+	"break -$full " {
+	    send_gdb "\n"
+	    gdb_test_multiple "" $tst {
+		-re "missing argument for \"-$full\".*$gdb_prompt " {
+		    pass $tst
+		}
+	    }
+	}
+    }
+}
+
+set tst "complete unique function name"
+send_gdb "break -function mai\t"
+gdb_test_multiple "" $tst {
+    "break -function mai\\\x07n" {
+	send_gdb "\n"
+	gdb_test "" ".*Breakpoint \[0-9\]+.*" $tst
+	gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+    }
+}
+
+set tst "complete non-unique function name"
+send_gdb "break -function myfunc\t"
+gdb_test_multiple "" $tst {
+    "break -function myfunc\\\x07tion" {
+	send_gdb "\t\t"
+	gdb_test_multiple "" $tst {
+	    -re "\\\x07\r\nmyfunction\[ \t\]+myfunction2\[ \t\]+myfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
+		gdb_test "2" ".*Breakpoint \[0-9\]+.*" $tst
+		gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
+	    }
+	}
+    }
+}
+
+set tst "complete non-existant function name"
+send_gdb "break -function foo\t"
+gdb_test_multiple "" $tst {
+    "break -function foo\\\x07" {
+	send_gdb "\t\t"
+	gdb_test_multiple "" $tst {
+	    -re "\\\x07\\\x07" {
+		send_gdb "\n"
+		gdb_test "" {Function "foo" not defined.} $tst
+	    }
+	}
+    }
+}
+
+set tst "complete unique file name"
+send_gdb "break -source 3ex\t"
+gdb_test_multiple "" $tst {
+    "break -source 3explicit.c " {
+	send_gdb "\n"
+	gdb_test "" \
+	    {Source filename requires function, label, or line offset.} $tst
+    }
+}
+
+set tst "complete non-unique file name"
+send_gdb "break -source exp\t"
+gdb_test_multiple "" $tst {
+    "break -source exp\\\x07licit" {
+	send_gdb "\t\t"
+	gdb_test_multiple "" $tst {
+	    -re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+\r\n$gdb_prompt" {
+		send_gdb "\n"
+		gdb_test "" \
+		    {Source filename requires function, label, or line offset.} \
+		    $tst
+	    }
+	}
+    }
+
+    "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
+    }
+}
+
+unset -nocomplain lineno tst
diff --git a/gdb/testsuite/gdb.linespec/explicit2.c b/gdb/testsuite/gdb.linespec/explicit2.c
new file mode 100644
index 0000000..218cccb
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/explicit2.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int myfunction3 (int arg);
+
+int
+myfunction2 (int arg)
+{
+  return myfunction3 (arg);
+}
diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp
index 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] 25+ messages in thread

* [PATCH v3 8/9] Explicit locations: MI support for explicit locations
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (2 preceding siblings ...)
  2015-02-17 22:06 ` [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
@ 2015-02-17 22:07 ` Keith Seitz
  2015-03-01 21:15   ` Doug Evans
  2015-02-17 22:07 ` [PATCH v3 6/9] Explicit locations: introduce " Keith Seitz
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:07 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 20546f6..7ffeb59 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -2408,7 +2408,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 ".*".
@@ -2423,17 +2423,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] 25+ messages in thread

* [PATCH v3 3/9] Explicit locations: use new location API
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (6 preceding siblings ...)
  2015-02-17 22:07 ` [PATCH v3 7/9] Explicit locations: add UI features for CLI Keith Seitz
@ 2015-02-17 22:07 ` Keith Seitz
  2015-03-01 20:54   ` Doug Evans
  2015-02-17 22:50 ` [PATCH v3 9/9] Explicit locations: documentation updates Keith Seitz
  2015-02-23  4:17 ` [PATCH v3 0/9] Locations API Doug Evans
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:07 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.
	* 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          |   19 +
 gdb/breakpoint.c                 |  683 +++++++++++++++++++++++---------------
 gdb/breakpoint.h                 |   22 +
 gdb/cli/cli-cmds.c               |   47 ++-
 gdb/elfread.c                    |    4 
 gdb/linespec.c                   |  148 ++++++--
 gdb/linespec.h                   |   12 -
 gdb/mi/mi-cmd-break.c            |   12 +
 gdb/probe.c                      |   20 +
 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                   |   13 +
 gdb/tracepoint.c                 |   16 +
 gdb/tracepoint.h                 |    2 
 18 files changed, 686 insertions(+), 388 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 954e98b..551f722 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
@@ -206,27 +207,33 @@ re_set_exception_catchpoint (struct breakpoint *self)
   volatile struct gdb_exception e;
   struct cleanup *cleanup;
   enum exception_event_kind kind = classify_exception_breakpoint (self);
+  struct event_location *location;
+  char *p;
 
   /* We first try to use the probe interface.  */
+  p = ASTRDUP (exception_functions[kind].probe);
+  location = new_linespec_location (&p);
+  cleanup = make_cleanup_delete_event_location (location);
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {
-      char *spec = ASTRDUP (exception_functions[kind].probe);
-
-      sals = parse_probes (&spec, NULL);
+      sals = parse_probes (location, NULL);
     }
+  do_cleanups (cleanup);
 
   if (e.reason < 0)
     {
       volatile struct gdb_exception ex;
+      char *func = ASTRDUP (exception_functions[kind].function);
 
       /* Using the probe interface failed.  Let's fallback to the normal
 	 catchpoint mode.  */
+      location = new_linespec_location (&func);
+      cleanup = make_cleanup_delete_event_location (location);
       TRY_CATCH (ex, RETURN_MASK_ERROR)
 	{
-	  char *spec = ASTRDUP (exception_functions[kind].function);
-
-	  self->ops->decode_location (self, &spec, &sals);
+	  self->ops->decode_location (self, location, &sals);
 	}
+      do_cleanups (cleanup);
 
       /* NOT_FOUND_ERROR just means the breakpoint will be pending, so
 	 let it through.  */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c7d6c98..5c3be10 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -68,6 +68,7 @@
 #include "dummy-frame.h"
 #include "interps.h"
 #include "format.h"
+#include "location.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -109,10 +110,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 *,
@@ -122,8 +123,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);
 
@@ -3401,6 +3403,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);
 
@@ -3425,7 +3428,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)
         {
@@ -3492,6 +3496,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,
@@ -3506,7 +3511,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;
 	    }
 
@@ -3521,6 +3527,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;
@@ -3543,7 +3550,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;
 	}
     }
@@ -3574,6 +3582,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);
 
@@ -3599,7 +3608,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;
     }
   }
@@ -3623,6 +3633,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);
 
@@ -3663,13 +3674,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;
 	    }
 
@@ -3702,7 +3715,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;
     }
 
@@ -3823,7 +3837,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;
@@ -5994,7 +6008,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 
@@ -6030,7 +6045,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
@@ -6499,8 +6515,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));
     }
 }
 
@@ -7270,6 +7288,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
@@ -7610,15 +7629,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);
 
@@ -9450,13 +9473,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,
@@ -9505,7 +9529,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;
@@ -9522,13 +9549,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;
@@ -9584,19 +9611,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,
@@ -9621,7 +9655,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,
@@ -9665,17 +9699,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,
@@ -9686,84 +9720,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
-      || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
+  struct symtab_and_line cursal;
+
+  if (event_location_type (location) == LINESPEC_LOCATION)
     {
-      /* The last displayed codepoint, if it's valid, is our default breakpoint
-         address.  */
-      if (last_displayed_sal_is_valid ())
+      const char *address = get_linespec_location (location);
+
+      if (address == NULL)
 	{
-	  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);
+	  /* 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);
 }
 
 
@@ -9909,19 +9956,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);
@@ -9953,20 +10000,30 @@ 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.
+/* 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_ARG
+   parameter.
+
+   If PARSE_ARG 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_ARG is non-zero and LOCATION is a linespec location,
+   this function will attempt to extract the location, condition, thread,
+   and extra string from the linespec stored in LOCATION.
+   For non-linespec locations EXTRA_STRING is parsed for condition, thread,
+   and extra string.
+
    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.  */
+   from the internal breakpoint count.
+
+   Returns true if any breakpoint was created; false otherwise.  */
 
 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 tempflag, enum bptype type_wanted,
@@ -9977,8 +10034,6 @@ create_breakpoint (struct gdbarch *gdbarch,
 		   unsigned flags)
 {
   volatile struct gdb_exception e;
-  char *copy_arg = NULL;
-  char *addr_start = arg;
   struct linespec_result canonical;
   struct cleanup *old_chain;
   struct cleanup *bkpt_chain = NULL;
@@ -9988,12 +10043,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_CATCH (e, RETURN_MASK_ALL)
     {
-      ops->create_sals_from_location (&arg, &canonical, type_wanted,
-				      addr_start, &copy_arg);
+      ops->create_sals_from_location (location, &canonical, type_wanted);
     }
 
   /* If caller is interested in rc value from parse, set value.  */
@@ -10027,17 +10085,7 @@ 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);
-	  }
 	  break;
 	default:
 	  throw_exception (e);
@@ -10082,6 +10130,8 @@ create_breakpoint (struct gdbarch *gdbarch,
      breakpoint.  */
   if (!pending)
     {
+      char *arg = extra_string;
+
       if (parse_arg)
         {
 	  char *rest;
@@ -10102,11 +10152,13 @@ create_breakpoint (struct gdbarch *gdbarch,
 	    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 && arg != NULL && *arg != '\0')
+		error (_("Garbage '%s' at end of location"), arg);
 
 	  /* Create a private copy of condition string.  */
 	  if (cond_string)
@@ -10132,8 +10184,6 @@ create_breakpoint (struct gdbarch *gdbarch,
     {
       struct breakpoint *b;
 
-      make_cleanup (xfree, copy_arg);
-
       if (is_tracepoint_type (type_wanted))
 	{
 	  struct tracepoint *t;
@@ -10145,8 +10195,21 @@ 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);
+
+	  set_event_location_string (b->location, new);
+	  xfree (new);
+	}
 
-      b->addr_string = copy_arg;
       if (parse_arg)
 	b->cond_string = NULL;
       else
@@ -10159,7 +10222,15 @@ create_breakpoint (struct gdbarch *gdbarch,
 	    }
 	  b->cond_string = cond_string;
 	}
-      b->extra_string = NULL;
+
+      /* Make a private copy of extra_string for the breakpoint.  */
+      if (extra_string != NULL)
+	{
+	  b->extra_string = xstrdup (extra_string);
+	  make_cleanup (xfree, b->extra_string);
+	}
+      else
+	b->extra_string = NULL;
       b->ignore_count = ignore_count;
       b->disposition = tempflag ? disp_del : disp_donttouch;
       b->condition_not_parsed = 1;
@@ -10206,16 +10277,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,
@@ -10224,6 +10300,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.  */
@@ -10390,9 +10467,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,
@@ -10401,6 +10484,7 @@ dprintf_command (char *arg, int from_tty)
 		     1 /* enabled */,
 		     0 /* internal */,
 		     0);
+  do_cleanups (cleanup);
 }
 
 static void
@@ -10545,8 +10629,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);
 }
 
@@ -10597,6 +10682,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)
@@ -10616,9 +10702,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."));
@@ -10648,7 +10735,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);
 
@@ -10663,8 +10752,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)
@@ -10691,8 +10778,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);
@@ -11819,21 +11906,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)
@@ -11919,6 +12010,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
@@ -12074,7 +12167,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;
 }
 
@@ -13030,7 +13124,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
     {
@@ -13052,7 +13147,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)
@@ -13094,9 +13190,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 *
@@ -13189,11 +13285,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 ();
 }
@@ -13215,7 +13310,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 ();
@@ -13266,9 +13362,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;
     }
@@ -13420,18 +13516,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
@@ -13456,10 +13551,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.  */
@@ -13659,26 +13755,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"));
 }
@@ -13760,7 +13853,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)
@@ -13768,13 +13862,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
@@ -13799,10 +13891,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;
@@ -13811,22 +13904,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;
@@ -13865,7 +13958,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);
 }
@@ -13912,19 +14006,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;
+
+  arg = arg_start = get_linespec_location (location);
+  lsal.sals = decode_static_tracepoint_spec (&arg);
 
-  lsal.sals = decode_static_tracepoint_spec (arg);
+  if (canonical != NULL)
+    {
+      char *str;
+      struct cleanup *cleanup;
 
-  *copy_arg = savestring (addr_start, *arg - addr_start);
+      str = savestring (arg_start, arg - arg_start);
+      cleanup = make_cleanup (xfree, str);
+      canonical->location = new_linespec_location (&str);
+      do_cleanups (cleanup);
+    }
 
-  canonical->addr_string = xstrdup (*copy_arg);
-  lsal.canonical = xstrdup (*copy_arg);
+  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
   VEC_safe_push (linespec_sals, canonical->sals, &lsal);
 }
 
@@ -13957,17 +14060,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,
@@ -13988,12 +14091,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];
@@ -14325,10 +14430,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);
 
@@ -14369,10 +14476,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.  */
@@ -14529,22 +14639,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};
   volatile struct gdb_exception e;
 
   gdb_assert (b->ops != NULL);
-  s = addr_string;
 
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {
-      b->ops->decode_location (b, &s, &sals);
+      b->ops->decode_location (b, location, &sals);
     }
   if (e.reason < 0)
     {
@@ -14582,21 +14691,37 @@ 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)
 	{
-	  char *cond_string, *extra_string;
-	  int thread, task;
+	  const char *s = b->extra_string;
 
-	  find_condition_and_thread (s, sals.sals[0].pc,
-				     &cond_string, &thread, &task,
-				     &extra_string);
-	  if (cond_string)
-	    b->cond_string = cond_string;
-	  b->thread = thread;
-	  b->task = task;
-	  if (extra_string)
-	    b->extra_string = extra_string;
-	  b->condition_not_parsed = 0;
+	  if (s != NULL && *s != '\0')
+	    {
+	      char *cond_string, *extra_string;
+	      int thread, task;
+	      const char *orig = s;
+
+	      find_condition_and_thread (s, sals.sals[0].pc,
+					 &cond_string, &thread, &task,
+					 &extra_string);
+	      if (cond_string)
+		b->cond_string = cond_string;
+	      b->thread = thread;
+	      b->task = task;
+	      if (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))
@@ -14622,16 +14747,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);
@@ -14646,12 +14771,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
@@ -14682,13 +14806,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);
@@ -15421,16 +15546,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 */,
@@ -15439,14 +15568,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 */,
@@ -15455,6 +15590,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.  */
@@ -15463,17 +15599,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 && strncmp (arg, "-m", 2) == 0 && 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 */,
@@ -15482,6 +15627,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
@@ -15513,6 +15659,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;
@@ -15535,9 +15683,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 */,
@@ -15548,7 +15698,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 42c7427..5027ff4 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
@@ -560,8 +561,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
@@ -582,8 +584,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.  */
@@ -682,17 +685,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;
@@ -1274,7 +1277,8 @@ enum breakpoint_create_flags
     CREATE_BREAKPOINT_FLAGS_INSERTED = 1 << 0
   };
 
-extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
+extern int create_breakpoint (struct gdbarch *gdbarch,
+			      const struct event_location *location,
 			      char *cond_string, int thread,
 			      char *extra_string,
 			      int parse_arg,
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index e46f036..ebca1fc 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 fbe3917..03a6a4f 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/linespec.c b/gdb/linespec.c
index f2ae93b..29e32e3 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);
@@ -280,8 +281,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;
@@ -319,7 +320,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 *);
 
@@ -433,10 +434,9 @@ linespec_lexer_lex_keyword (const char *p)
 	  int len = strlen (linespec_keywords[i]);
 
 	  /* If P begins with one of the keywords and the next
-	     character is not a valid identifier character,
-	     we have found a keyword.  */
+	     character is whitespace, we have found a keyword.  */
 	  if (strncmp (p, linespec_keywords[i], len) == 0
-	      && !(isalnum (p[len]) || p[len] == '_'))
+	      && isspace (p[len]))
 	    return linespec_keywords[i];
 	}
     }
@@ -1765,21 +1765,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);
@@ -1828,8 +1836,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);
     }
 }
 
@@ -2097,8 +2107,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:
 
@@ -2147,10 +2155,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;
@@ -2161,17 +2169,17 @@ 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;
 	}
     }
@@ -2180,8 +2188,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
      Consider "b thread thread 42".  */
   parser->keyword_ok = 0;
 
-  parser->lexer.saved_arg = *argptr;
-  parser->lexer.stream = argptr;
+  parser->lexer.saved_arg = arg;
+  parser->lexer.stream = arg;
   file_exception.reason = 0;
 
   /* Initialize the default symtab and line offset.  */
@@ -2189,7 +2197,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 		       &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;
 
@@ -2373,6 +2381,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;
@@ -2437,7 +2446,7 @@ linespec_lex_to_end (char **stringp)
   parser.lexer.saved_arg = *stringp;
   parser.keyword_ok = 1;
   orig = p = *stringp;
-  parser.lexer.stream = &p;
+  parser.lexer.stream = p;
 
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {
@@ -2474,10 +2483,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:
+      {
+	volatile struct gdb_exception except;
+
+	TRY_CATCH (except, RETURN_MASK_ERROR)
+	  {
+	    result = parse_linespec (parser, get_linespec_location (location));
+	  }
+
+	if (except.reason < 0)
+	  throw_exception (except);
+      }
+      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,
@@ -2488,7 +2529,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'.  */
@@ -2504,13 +2544,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.  */
@@ -2554,23 +2591,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;
@@ -2583,6 +2617,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."));
@@ -2591,11 +2627,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;
 }
 
@@ -2605,19 +2645,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;
 }
 
@@ -2670,7 +2716,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;
@@ -2688,7 +2734,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);
@@ -2702,9 +2748,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;
@@ -2713,17 +2759,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;
@@ -3800,7 +3852,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 728b1bd..5f5bc71 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 56b5fc1..61236ee 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -30,6 +30,8 @@
 #include "gdb_regex.h"
 #include "frame.h"
 #include "arch-utils.h"
+#include "location.h"
+
 #include <ctype.h>
 
 typedef struct bound_probe bound_probe_s;
@@ -40,23 +42,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);
@@ -167,12 +170,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 1dd582d..33c6d1d 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.  */
@@ -201,9 +203,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 7807e4e..ecd55e4 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;
@@ -368,7 +369,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);
@@ -376,8 +377,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);
@@ -653,8 +653,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 94f19e0..bbb408a 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";
@@ -167,7 +168,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
   int internal_bp = 0;
   CORE_ADDR finish_pc, pc;
   volatile struct gdb_exception except;
-  char *addr_str, small_buf[100];
+  char small_buf[100], *p;
   struct symbol *function;
 
   if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
@@ -286,13 +287,17 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
+      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,
@@ -300,6 +305,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
                          AUTO_BOOLEAN_TRUE,
                          &bkpt_breakpoint_ops,
                          0, 1, internal_bp, 0);
+      do_cleanups (back_to);
     }
   GDB_PY_SET_HANDLE_EXCEPTION (except);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 344d8d2..b34d036 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";
@@ -713,13 +714,13 @@ 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;
   volatile struct gdb_exception except;
+  struct event_location *location;
 
   if (! PyArg_ParseTuple (args, "|s", &arg))
     return NULL;
@@ -727,14 +728,16 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
   cleanups = make_cleanup (null_cleanup, NULL);
 
   sals.sals = NULL;
+  if (arg != NULL)
+    {
+      location = new_linespec_location (&arg);
+      make_cleanup_delete_event_location (location);
+    }
+
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
       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 ();
@@ -745,10 +748,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
     }
 
   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)
     {
@@ -792,9 +792,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 dbfc10b..329c300 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>
 
@@ -10672,13 +10673,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 36ad312..86af2ae 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;
@@ -1955,7 +1955,9 @@ spu_catch_start (struct objfile *objfile)
   struct bound_minimal_symbol minsym;
   struct compunit_symtab *cust;
   CORE_ADDR pc;
-  char buf[32];
+  struct event_location *location;
+  struct cleanup *back_to;
+  char *p;
 
   /* Do this only if requested by "set spu stop-on-load on".  */
   if (!spu_stop_on_load_p)
@@ -1999,8 +2001,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 = ASTRDUP (core_addr_to_string (pc));
+  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 +2013,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 0774f5e..a4167ae 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] 25+ messages in thread

* [PATCH v3 9/9] Explicit locations: documentation updates
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (7 preceding siblings ...)
  2015-02-17 22:07 ` [PATCH v3 3/9] Explicit locations: use new location API Keith Seitz
@ 2015-02-17 22:50 ` Keith Seitz
  2015-03-01 21:25   ` Doug Evans
  2015-02-23  4:17 ` [PATCH v3 0/9] Locations API Doug Evans
  9 siblings, 1 reply; 25+ messages in thread
From: Keith Seitz @ 2015-02-17 22:50 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                |   69 +++++++-----
 gdb/doc/gdb.texinfo             |  234 +++++++++++++++++++++++++--------------
 gdb/testsuite/gdb.base/help.exp |    2 
 4 files changed, 194 insertions(+), 115 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 624f508..0b4581e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -193,6 +193,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 046219b..a902b7b 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -16114,25 +16114,44 @@ 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) or `-probe-stap' (for a SystemTap 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\
@@ -16627,20 +16646,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);
 
@@ -16833,7 +16849,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."));
@@ -16845,31 +16861,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\
@@ -17021,11 +17033,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 d1f22de..bce6482 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6016,9 +6016,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.
 
@@ -7444,21 +7444,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}.
@@ -7483,11 +7483,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}
@@ -7526,25 +7531,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{Explict 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
@@ -7569,22 +7642,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
@@ -7902,9 +7959,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
 
@@ -7922,7 +7979,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.
@@ -8032,7 +8089,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}.
@@ -11630,9 +11687,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
@@ -11937,12 +11994,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
@@ -15822,14 +15878,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
@@ -16757,20 +16813,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
@@ -26474,6 +26527,7 @@ N.A.
 
 @subheading The @code{-break-insert} Command
 @findex -break-insert
+@anchor{-break-insert}
 
 @subsubheading Synopsis
 
@@ -26486,16 +26540,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
@@ -26587,17 +26660,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] 25+ messages in thread

* Re: [PATCH v3 0/9] Locations API
  2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
                   ` (8 preceding siblings ...)
  2015-02-17 22:50 ` [PATCH v3 9/9] Explicit locations: documentation updates Keith Seitz
@ 2015-02-23  4:17 ` Doug Evans
  9 siblings, 0 replies; 25+ messages in thread
From: Doug Evans @ 2015-02-23  4:17 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> This is the next revision of the locations/explicit locations mega-API
> change on which I've been working. The most important change in this
> revision is the removal of some previous ugliness introduced by the
> patch set to deal with advancing the input pointer for the CLI.
>
> In this version, all of this has been removed (even from decode_line*).
> This is now done (easily) by adding a new lexing function to find the
> end of the linespec.
>
> Thus, string_to_event_location can now treat all location types the same
> and advance the input pointer past the first terminated location string.
>
> General API usage now looks like:
>
> 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);
> }
>
> One note on this series... explicit-ui-cli will introduce a failing
> test because of gdb/17960 (internal-error when completing "source.c:func").
> This is trivially fixable after that patch has been committed.
>
> I figure there's no harm in delaying further review. There's still quite
> a way to go.
>
>
> ---
>
> 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

Hi.

I've read through the patchset and nothing stands out as needing
major discussion, it's all very straightforward now. Cool.
[I didn't dig into everything with a fine toothed comb,
but I did read it all.]

I've written down a few nits which I'll hopefully have time
this week to put into email. I first want to apply
all the patches and see how they look as a whole.

Thanks for sticking with it, this version is nice!

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

* Re: [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location"
  2015-02-17 22:06 ` [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
@ 2015-03-01 20:08   ` Doug Evans
  0 siblings, 0 replies; 25+ messages in thread
From: Doug Evans @ 2015-03-01 20:08 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.

Hi.

LGTM

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

* Re: [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API
  2015-02-17 22:06 ` [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
@ 2015-03-01 20:14   ` Doug Evans
  2015-05-07 16:59     ` Keith Seitz
  0 siblings, 1 reply; 25+ messages in thread
From: Doug Evans @ 2015-03-01 20:14 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.
>
> 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.

Hi.
A few comments inline.
grep for ^====

> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 00fb2cd..665853b 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -836,7 +836,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 \
> @@ -922,7 +922,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 solib-pa64.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 \
> @@ -1003,7 +1003,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 0d012b4..f2ae93b 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -2418,6 +2418,62 @@ 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 *p, *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.keyword_ok = 1;

====
parser.keyword_ok = 0; ?

> +  orig = p = *stringp;
> +  parser.lexer.stream = &p;
> +
> +  TRY_CATCH (e, RETURN_MASK_ERROR)
> +    {
> +      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 == '*')

====
Will this mis-parse an address appearing after the first token?
[IOW, *address must be the first token, right?]

> +	    {
> +	      const char *arg, *orig;
> +
> +	      orig = arg = *stringp;
> +	      (void) linespec_expression_to_pc (&arg);
> +	      PARSER_STREAM (&parser) += arg - orig;

====
How about: PARSER_STREAM (&parser) = arg; ?

> +	      break;
> +	    }
> +
> +	  token = linespec_lexer_consume_token (&parser);
> +
> +	  /* Keywords are okay after the first token.  */
> +	  parser.keyword_ok = 1;
> +	}
> +      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
> +    }
> +
> +  *stringp += PARSER_STREAM (&parser) - orig;

====
Similary, how about: *stringp = PARSER_STREAM (&parser); ?

> +  do_cleanups (cleanup);
> +}
> +
>  /* See linespec.h.  */
>  
>  void
> diff --git a/gdb/linespec.h b/gdb/linespec.h
> index 5520afa..728b1bd 100644
> --- a/gdb/linespec.h
> +++ b/gdb/linespec.h
> @@ -152,4 +152,8 @@ extern struct symtabs_and_lines decode_line_with_current_source (char *, int);
>  
>  extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
>  
> +/* 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] 25+ messages in thread

* Re: [PATCH v3 3/9] Explicit locations: use new location API
  2015-02-17 22:07 ` [PATCH v3 3/9] Explicit locations: use new location API Keith Seitz
@ 2015-03-01 20:54   ` Doug Evans
  2015-05-07 17:03     ` Keith Seitz
  0 siblings, 1 reply; 25+ messages in thread
From: Doug Evans @ 2015-03-01 20:54 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.
> 	* 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.

Hi.
A few comments inline.
grep for ^====

> 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 954e98b..551f722 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
> @@ -206,27 +207,33 @@ re_set_exception_catchpoint (struct breakpoint *self)
>    volatile struct gdb_exception e;
>    struct cleanup *cleanup;
>    enum exception_event_kind kind = classify_exception_breakpoint (self);
> +  struct event_location *location;
> +  char *p;
>  
>    /* We first try to use the probe interface.  */
> +  p = ASTRDUP (exception_functions[kind].probe);
> +  location = new_linespec_location (&p);
> +  cleanup = make_cleanup_delete_event_location (location);
>    TRY_CATCH (e, RETURN_MASK_ERROR)
>      {
> -      char *spec = ASTRDUP (exception_functions[kind].probe);
> -
> -      sals = parse_probes (&spec, NULL);
> +      sals = parse_probes (location, NULL);
>      }
> +  do_cleanups (cleanup);
>  
>    if (e.reason < 0)
>      {
>        volatile struct gdb_exception ex;
> +      char *func = ASTRDUP (exception_functions[kind].function);
>  
>        /* Using the probe interface failed.  Let's fallback to the normal
>  	 catchpoint mode.  */
> +      location = new_linespec_location (&func);
> +      cleanup = make_cleanup_delete_event_location (location);
>        TRY_CATCH (ex, RETURN_MASK_ERROR)
>  	{
> -	  char *spec = ASTRDUP (exception_functions[kind].function);
> -
> -	  self->ops->decode_location (self, &spec, &sals);
> +	  self->ops->decode_location (self, location, &sals);
>  	}
> +      do_cleanups (cleanup);
>  
>        /* NOT_FOUND_ERROR just means the breakpoint will be pending, so
>  	 let it through.  */
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index c7d6c98..5c3be10 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -68,6 +68,7 @@
>  #include "dummy-frame.h"
>  #include "interps.h"
>  #include "format.h"
> +#include "location.h"
>  
>  /* readline include files */
>  #include "readline/readline.h"
> @@ -109,10 +110,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 *,
> @@ -122,8 +123,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);
>  
> @@ -3401,6 +3403,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);
>  
> @@ -3425,7 +3428,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)
>          {
> @@ -3492,6 +3496,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,
> @@ -3506,7 +3511,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;
>  	    }
>  
> @@ -3521,6 +3527,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;
> @@ -3543,7 +3550,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;
>  	}
>      }
> @@ -3574,6 +3582,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);
>  
> @@ -3599,7 +3608,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;
>      }
>    }
> @@ -3623,6 +3633,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);
>  
> @@ -3663,13 +3674,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;
>  	    }
>  
> @@ -3702,7 +3715,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;
>      }
>  
> @@ -3823,7 +3837,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;
> @@ -5994,7 +6008,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 
> @@ -6030,7 +6045,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
> @@ -6499,8 +6515,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));
>      }
>  }
>  
> @@ -7270,6 +7288,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
> @@ -7610,15 +7629,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);
>  
> @@ -9450,13 +9473,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,
> @@ -9505,7 +9529,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;
> @@ -9522,13 +9549,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;
> @@ -9584,19 +9611,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,
> @@ -9621,7 +9655,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,
> @@ -9665,17 +9699,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,
> @@ -9686,84 +9720,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
> -      || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
> +  struct symtab_and_line cursal;
> +
> +  if (event_location_type (location) == LINESPEC_LOCATION)
>      {
> -      /* The last displayed codepoint, if it's valid, is our default breakpoint
> -         address.  */
> -      if (last_displayed_sal_is_valid ())
> +      const char *address = get_linespec_location (location);
> +
> +      if (address == NULL)
>  	{
> -	  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);
> +	  /* 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);
>  }
>  
>  
> @@ -9909,19 +9956,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);
> @@ -9953,20 +10000,30 @@ 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.
> +/* 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_ARG
> +   parameter.
> +
> +   If PARSE_ARG 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_ARG is non-zero and LOCATION is a linespec location,
> +   this function will attempt to extract the location, condition, thread,
> +   and extra string from the linespec stored in LOCATION.
> +   For non-linespec locations EXTRA_STRING is parsed for condition, thread,
> +   and extra string.
> +
>     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.  */
> +   from the internal breakpoint count.
> +
> +   Returns true if any breakpoint was created; false otherwise.  */
>  
>  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,

====
Rename parse_arg to parse_location or parse_extra?
["parse_arg" made sense when "arg" was a parameter, but it's confusing now]

>  		   int tempflag, enum bptype type_wanted,
> @@ -9977,8 +10034,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>  		   unsigned flags)
>  {
>    volatile struct gdb_exception e;
> -  char *copy_arg = NULL;
> -  char *addr_start = arg;
>    struct linespec_result canonical;
>    struct cleanup *old_chain;
>    struct cleanup *bkpt_chain = NULL;
> @@ -9988,12 +10043,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_CATCH (e, RETURN_MASK_ALL)
>      {
> -      ops->create_sals_from_location (&arg, &canonical, type_wanted,
> -				      addr_start, &copy_arg);
> +      ops->create_sals_from_location (location, &canonical, type_wanted);
>      }
>  
>    /* If caller is interested in rc value from parse, set value.  */
> @@ -10027,17 +10085,7 @@ 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);
> -	  }
>  	  break;
>  	default:
>  	  throw_exception (e);
> @@ -10082,6 +10130,8 @@ create_breakpoint (struct gdbarch *gdbarch,
>       breakpoint.  */
>    if (!pending)
>      {
> +      char *arg = extra_string;

====
I gather having "arg" is here to minimize changes, but it reduces
readability a bit.

> +
>        if (parse_arg)
>          {
>  	  char *rest;
> @@ -10102,11 +10152,13 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	    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 && arg != NULL && *arg != '\0')
> +		error (_("Garbage '%s' at end of location"), arg);
>  
>  	  /* Create a private copy of condition string.  */
>  	  if (cond_string)
> @@ -10132,8 +10184,6 @@ create_breakpoint (struct gdbarch *gdbarch,
>      {
>        struct breakpoint *b;
>  
> -      make_cleanup (xfree, copy_arg);
> -
>        if (is_tracepoint_type (type_wanted))
>  	{
>  	  struct tracepoint *t;
> @@ -10145,8 +10195,21 @@ 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);
> +
> +	  set_event_location_string (b->location, new);
> +	  xfree (new);
> +	}
>  
> -      b->addr_string = copy_arg;
>        if (parse_arg)
>  	b->cond_string = NULL;
>        else
> @@ -10159,7 +10222,15 @@ create_breakpoint (struct gdbarch *gdbarch,
>  	    }
>  	  b->cond_string = cond_string;
>  	}
> -      b->extra_string = NULL;
> +
> +      /* Make a private copy of extra_string for the breakpoint.  */
> +      if (extra_string != NULL)
> +	{
> +	  b->extra_string = xstrdup (extra_string);
> +	  make_cleanup (xfree, b->extra_string);

====
This cleanup is odd. I would have expected a cleanup for "b" to
completely clean itself up. However, it looks like no cleanup for "b"
is ever created. So that's an existing bug which I wouldn't impose
on this patchset to fix, but OTOH this cleanup still feels wrong.

Also, the docs of extra_string in breakpoint.h are lacking.
It's not something that has to be fixed with this patchset,
but I'm having to dig too deep to figure out how extra_string
is different from cond_string. Can I trouble you to clarify things?

> +	}
> +      else
> +	b->extra_string = NULL;
>        b->ignore_count = ignore_count;
>        b->disposition = tempflag ? disp_del : disp_donttouch;
>        b->condition_not_parsed = 1;
> @@ -10206,16 +10277,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)

====
Extra space before &&.

>      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,
> @@ -10224,6 +10300,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.  */
> @@ -10390,9 +10467,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,
> @@ -10401,6 +10484,7 @@ dprintf_command (char *arg, int from_tty)
>  		     1 /* enabled */,
>  		     0 /* internal */,
>  		     0);
> +  do_cleanups (cleanup);
>  }
>  
>  static void
> @@ -10545,8 +10629,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);
>  }
>  
> @@ -10597,6 +10682,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)
> @@ -10616,9 +10702,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."));
> @@ -10648,7 +10735,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);
>  
> @@ -10663,8 +10752,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)
> @@ -10691,8 +10778,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);
> @@ -11819,21 +11906,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)
> @@ -11919,6 +12010,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
> @@ -12074,7 +12167,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;
>  }
>  
> @@ -13030,7 +13124,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
>      {
> @@ -13052,7 +13147,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)
> @@ -13094,9 +13190,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 *
> @@ -13189,11 +13285,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 ();
>  }
> @@ -13215,7 +13310,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 ();
> @@ -13266,9 +13362,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;
>      }
> @@ -13420,18 +13516,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
> @@ -13456,10 +13551,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.  */
> @@ -13659,26 +13755,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"));
>  }
> @@ -13760,7 +13853,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)
> @@ -13768,13 +13862,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
> @@ -13799,10 +13891,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;
> @@ -13811,22 +13904,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;
> @@ -13865,7 +13958,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);
>  }
> @@ -13912,19 +14006,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;
> +
> +  arg = arg_start = get_linespec_location (location);
> +  lsal.sals = decode_static_tracepoint_spec (&arg);
>  
> -  lsal.sals = decode_static_tracepoint_spec (arg);
> +  if (canonical != NULL)
> +    {
> +      char *str;
> +      struct cleanup *cleanup;
>  
> -  *copy_arg = savestring (addr_start, *arg - addr_start);
> +      str = savestring (arg_start, arg - arg_start);
> +      cleanup = make_cleanup (xfree, str);
> +      canonical->location = new_linespec_location (&str);
> +      do_cleanups (cleanup);
> +    }
>  
> -  canonical->addr_string = xstrdup (*copy_arg);
> -  lsal.canonical = xstrdup (*copy_arg);
> +  lsal.canonical = xstrdup (event_location_to_string (canonical->location));
>    VEC_safe_push (linespec_sals, canonical->sals, &lsal);
>  }
>  
> @@ -13957,17 +14060,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,
> @@ -13988,12 +14091,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];
> @@ -14325,10 +14430,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);
>  
> @@ -14369,10 +14476,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.  */
> @@ -14529,22 +14639,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};
>    volatile struct gdb_exception e;
>  
>    gdb_assert (b->ops != NULL);
> -  s = addr_string;
>  
>    TRY_CATCH (e, RETURN_MASK_ERROR)
>      {
> -      b->ops->decode_location (b, &s, &sals);
> +      b->ops->decode_location (b, location, &sals);
>      }
>    if (e.reason < 0)
>      {
> @@ -14582,21 +14691,37 @@ 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)
>  	{
> -	  char *cond_string, *extra_string;
> -	  int thread, task;
> +	  const char *s = b->extra_string;
>  
> -	  find_condition_and_thread (s, sals.sals[0].pc,
> -				     &cond_string, &thread, &task,
> -				     &extra_string);
> -	  if (cond_string)
> -	    b->cond_string = cond_string;
> -	  b->thread = thread;
> -	  b->task = task;
> -	  if (extra_string)
> -	    b->extra_string = extra_string;
> -	  b->condition_not_parsed = 0;
> +	  if (s != NULL && *s != '\0')

====
If we have a rule that b->extra_string is never "" (only NULL) then
we can simplify this, and even remove this extra nested "if".
E.g., just have

+      if (b->condition_not_parsed && b->extra_string != NULL)

> +	    {
> +	      char *cond_string, *extra_string;
> +	      int thread, task;
> +	      const char *orig = s;
> +
> +	      find_condition_and_thread (s, sals.sals[0].pc,
> +					 &cond_string, &thread, &task,
> +					 &extra_string);
> +	      if (cond_string)
> +		b->cond_string = cond_string;
> +	      b->thread = thread;
> +	      b->task = task;
> +	      if (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))
> @@ -14622,16 +14747,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);
> @@ -14646,12 +14771,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
> @@ -14682,13 +14806,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);
> @@ -15421,16 +15546,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 */,
> @@ -15439,14 +15568,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 */,
> @@ -15455,6 +15590,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.  */
> @@ -15463,17 +15599,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 && strncmp (arg, "-m", 2) == 0 && 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 */,
> @@ -15482,6 +15627,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
> @@ -15513,6 +15659,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;
> @@ -15535,9 +15683,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 */,
> @@ -15548,7 +15698,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 42c7427..5027ff4 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
> @@ -560,8 +561,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
> @@ -582,8 +584,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.  */
> @@ -682,17 +685,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;
> @@ -1274,7 +1277,8 @@ enum breakpoint_create_flags
>      CREATE_BREAKPOINT_FLAGS_INSERTED = 1 << 0
>    };
>  
> -extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
> +extern int create_breakpoint (struct gdbarch *gdbarch,
> +			      const struct event_location *location,
>  			      char *cond_string, int thread,
>  			      char *extra_string,
>  			      int parse_arg,
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index e46f036..ebca1fc 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 fbe3917..03a6a4f 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/linespec.c b/gdb/linespec.c
> index f2ae93b..29e32e3 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);
> @@ -280,8 +281,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;
> @@ -319,7 +320,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 *);
>  
> @@ -433,10 +434,9 @@ linespec_lexer_lex_keyword (const char *p)
>  	  int len = strlen (linespec_keywords[i]);
>  
>  	  /* If P begins with one of the keywords and the next
> -	     character is not a valid identifier character,
> -	     we have found a keyword.  */
> +	     character is whitespace, we have found a keyword.  */
>  	  if (strncmp (p, linespec_keywords[i], len) == 0
> -	      && !(isalnum (p[len]) || p[len] == '_'))
> +	      && isspace (p[len]))

====
I think I'm ok with this change, but it seems separate from this patchset.
Submit it separately?

>  	    return linespec_keywords[i];
>  	}
>      }
> @@ -1765,21 +1765,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);

====
No need to make this change now (assuming it's doable),
but I'm curious if the parser needs to modify its argument
or whether we can pass a const char * and remove the ASTRDUP here
(and elsewhere).

> +      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);
> @@ -1828,8 +1836,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);
>      }
>  }
>  
> @@ -2097,8 +2107,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:
>  
> @@ -2147,10 +2155,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;
> @@ -2161,17 +2169,17 @@ 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;
>  	}
>      }
> @@ -2180,8 +2188,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
>       Consider "b thread thread 42".  */
>    parser->keyword_ok = 0;
>  
> -  parser->lexer.saved_arg = *argptr;
> -  parser->lexer.stream = argptr;
> +  parser->lexer.saved_arg = arg;
> +  parser->lexer.stream = arg;
>    file_exception.reason = 0;
>  
>    /* Initialize the default symtab and line offset.  */
> @@ -2189,7 +2197,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
>  		       &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;
>  
> @@ -2373,6 +2381,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;
> @@ -2437,7 +2446,7 @@ linespec_lex_to_end (char **stringp)
>    parser.lexer.saved_arg = *stringp;
>    parser.keyword_ok = 1;
>    orig = p = *stringp;
> -  parser.lexer.stream = &p;
> +  parser.lexer.stream = p;
>  
>    TRY_CATCH (e, RETURN_MASK_ERROR)
>      {
> @@ -2474,10 +2483,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:
> +      {
> +	volatile struct gdb_exception except;
> +
> +	TRY_CATCH (except, RETURN_MASK_ERROR)
> +	  {
> +	    result = parse_linespec (parser, get_linespec_location (location));
> +	  }
> +
> +	if (except.reason < 0)
> +	  throw_exception (except);
> +      }
> +      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,
> @@ -2488,7 +2529,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'.  */
> @@ -2504,13 +2544,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.  */
> @@ -2554,23 +2591,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;
> @@ -2583,6 +2617,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."));
> @@ -2591,11 +2627,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;
>  }
>  
> @@ -2605,19 +2645,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;
>  }
>  
> @@ -2670,7 +2716,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;
> @@ -2688,7 +2734,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);
> @@ -2702,9 +2748,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;
> @@ -2713,17 +2759,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;
> @@ -3800,7 +3852,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 728b1bd..5f5bc71 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 56b5fc1..61236ee 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -30,6 +30,8 @@
>  #include "gdb_regex.h"
>  #include "frame.h"
>  #include "arch-utils.h"
> +#include "location.h"
> +
>  #include <ctype.h>
>  
>  typedef struct bound_probe bound_probe_s;
> @@ -40,23 +42,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);
> @@ -167,12 +170,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 1dd582d..33c6d1d 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.  */
> @@ -201,9 +203,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 7807e4e..ecd55e4 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;
> @@ -368,7 +369,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);
> @@ -376,8 +377,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);
> @@ -653,8 +653,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 94f19e0..bbb408a 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";
> @@ -167,7 +168,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>    int internal_bp = 0;
>    CORE_ADDR finish_pc, pc;
>    volatile struct gdb_exception except;
> -  char *addr_str, small_buf[100];
> +  char small_buf[100], *p;
>    struct symbol *function;
>  
>    if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
> @@ -286,13 +287,17 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>  
>    TRY_CATCH (except, RETURN_MASK_ALL)
>      {
> +      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,
> @@ -300,6 +305,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
>                           AUTO_BOOLEAN_TRUE,
>                           &bkpt_breakpoint_ops,
>                           0, 1, internal_bp, 0);
> +      do_cleanups (back_to);
>      }
>    GDB_PY_SET_HANDLE_EXCEPTION (except);
>  
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 344d8d2..b34d036 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";
> @@ -713,13 +714,13 @@ 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;
>    volatile struct gdb_exception except;
> +  struct event_location *location;
>  
>    if (! PyArg_ParseTuple (args, "|s", &arg))
>      return NULL;
> @@ -727,14 +728,16 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>    cleanups = make_cleanup (null_cleanup, NULL);
>  
>    sals.sals = NULL;
> +  if (arg != NULL)
> +    {
> +      location = new_linespec_location (&arg);
> +      make_cleanup_delete_event_location (location);
> +    }
> +
>    TRY_CATCH (except, RETURN_MASK_ALL)
>      {
>        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 ();
> @@ -745,10 +748,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
>      }
>  
>    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)
>      {
> @@ -792,9 +792,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 dbfc10b..329c300 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>
>  
> @@ -10672,13 +10673,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 36ad312..86af2ae 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;
> @@ -1955,7 +1955,9 @@ spu_catch_start (struct objfile *objfile)
>    struct bound_minimal_symbol minsym;
>    struct compunit_symtab *cust;
>    CORE_ADDR pc;
> -  char buf[32];
> +  struct event_location *location;
> +  struct cleanup *back_to;
> +  char *p;
>  
>    /* Do this only if requested by "set spu stop-on-load on".  */
>    if (!spu_stop_on_load_p)
> @@ -1999,8 +2001,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 = ASTRDUP (core_addr_to_string (pc));

====
The leading '*' got dropped.
I can imagine this is just temporary anyway, as a later patch
(address locations) redoes this again.
I'm ok with leaving it as is, but I'd be remiss if I didn't
point it out.

> +  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 +2013,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 0774f5e..a4167ae 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] 25+ messages in thread

* Re: [PATCH v3 4/9] Explicit locations: introduce address locations
  2015-02-17 22:06 ` [PATCH v3 4/9] Explicit locations: introduce address locations Keith Seitz
@ 2015-03-01 21:03   ` Doug Evans
  2015-05-07 17:05     ` Keith Seitz
  0 siblings, 1 reply; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:03 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.

Hi.
A few comments inline.
grep for ^====

> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 5c3be10..ec0c6f8 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -7629,19 +7629,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);
>  
> @@ -9614,16 +9609,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 29e32e3..9c36d6c 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -316,7 +316,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,
> @@ -1768,79 +1768,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.  */
> @@ -1994,6 +1984,27 @@ 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);
> +
> +  if (self->canonical != NULL)
> +    self->canonical->location = new_address_location (address);

====
Modifying self->canonical->location is an undocumented side-effect.
Can you augment the function comment to document and explain this?

> +
> +  return sals;
> +}
> +
>  /* Create and return SALs from the linespec LS.  */
>  
>  static struct symtabs_and_lines
> @@ -2001,18 +2012,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;
> @@ -2110,8 +2110,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
> @@ -2207,33 +2206,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;
>  
> @@ -2457,20 +2430,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, *orig;
> -
> -	      orig = arg = *stringp;
> -	      (void) linespec_expression_to_pc (&arg);
> -	      PARSER_STREAM (&parser) += arg - orig;
> -	      break;
> -	    }
> -
>  	  token = linespec_lexer_consume_token (&parser);
>  
>  	  /* Keywords are okay after the first token.  */
> @@ -2508,6 +2467,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");
>      }
> @@ -2693,7 +2658,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 5f5bc71..8055f55 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);
>     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 bbb408a..d145dfa 100644
> --- a/gdb/python/py-finishbreakpoint.c
> +++ b/gdb/python/py-finishbreakpoint.c
> @@ -166,9 +166,8 @@ 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;
> +  CORE_ADDR pc;
>    volatile struct gdb_exception except;
> -  char small_buf[100], *p;
>    struct symbol *function;
>  
>    if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|OO", keywords,
> @@ -291,10 +290,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 86af2ae..61dc98d 100644
> --- a/gdb/spu-tdep.c
> +++ b/gdb/spu-tdep.c
> @@ -1957,7 +1957,6 @@ spu_catch_start (struct objfile *objfile)
>    CORE_ADDR pc;
>    struct event_location *location;
>    struct cleanup *back_to;
> -  char *p;
>  
>    /* Do this only if requested by "set spu stop-on-load on".  */
>    if (!spu_stop_on_load_p)
> @@ -2001,8 +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.  */
> -  p = ASTRDUP (core_addr_to_string (pc));
> -  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] 25+ messages in thread

* Re: [PATCH v3 5/9] Explicit locations: introduce probe locations
  2015-02-17 22:07 ` [PATCH v3 5/9] Explicit locations: introduce probe locations Keith Seitz
@ 2015-03-01 21:03   ` Doug Evans
  0 siblings, 0 replies; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:03 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] 25+ messages in thread

* Re: [PATCH v3 6/9] Explicit locations: introduce explicit locations
  2015-02-17 22:07 ` [PATCH v3 6/9] Explicit locations: introduce " Keith Seitz
@ 2015-03-01 21:04   ` Doug Evans
  0 siblings, 0 replies; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:04 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

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

* Re: [PATCH v3 7/9] Explicit locations: add UI features for CLI
  2015-02-17 22:07 ` [PATCH v3 7/9] Explicit locations: add UI features for CLI Keith Seitz
@ 2015-03-01 21:14   ` Doug Evans
  2015-05-07 17:07     ` Keith Seitz
  0 siblings, 1 reply; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:14 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.
> 	(location_completer): 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.

Hi.
A few comments inline.
grep for ^====

> diff --git a/gdb/completer.c b/gdb/completer.c
> index bfd2788..ec4ff17 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,175 @@ 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"));

====
No need for _() here.

> +    }
> +
> +  return matches;
> +}
> +
> +/* A convenience macro to (safely) back up P to the previous
> +   word.  */

====
This comment can be just one line.
I'd rather a comment run past the soft limit (and still fit within the
hard limit) than use an extra line just for one 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;
> +}
> +

====
Missing function comment.

> +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.  */

====
I couldn't get "b -<tab><tab>" to work. Can do?

> +
> +      /* 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;
> +	}
> +
> +      /* Now gather matches  */
> +      matches = collect_explicit_location_matches (location, what, new_word);

====
Something's not right here as "b -f <tab>" segv's because new_word is NULL.

> +    }
> +
> +  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.  */
> @@ -684,16 +869,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);
> @@ -762,14 +937,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 10ef7f9..c0ea3d9 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -327,8 +327,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.  */
> @@ -375,10 +373,9 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
>    return 1;
>  }
>  
> -/* Does P represent one of the keywords?  If so, return
> -   the keyword.  If not, return NULL.  */
> +/* See description in linespec.h.  */
>  
> -static const char *
> +const char *
>  linespec_lexer_lex_keyword (const char *p)
>  {
>    int i;
> @@ -400,10 +397,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;
> @@ -1119,7 +1115,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;
> @@ -1530,11 +1526,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 == '+')
> @@ -1548,6 +1545,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;
> @@ -3875,3 +3875,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 8055f55..6add0a7 100644
> --- a/gdb/linespec.h
> +++ b/gdb/linespec.h
> @@ -152,6 +152,36 @@ extern struct symtabs_and_lines decode_line_with_current_source (char *, int);
>  
>  extern struct symtabs_and_lines decode_line_with_last_displayed (char *, int);
>  
> +/* Parse a line offset from STRING.  */
> +
> +extern struct line_offset linespec_parse_line_offset (const char *string);
> +
> +/* A completion handler for locations.  */
> +
> +VEC (char_ptr) *location_completer (struct cmd_list_element *ignore,
> +				    const char *text, const char *word);
> +
> +/* Return the quote characters permitted by the linespec parser.  */
> +
> +extern const char *get_gdb_linespec_parser_quote_characters (void);
> +
> +/* Does STRING represent an Ada operator?  If so, return the length
> +   of the decoded operator name.  If not, return 0.  */
> +
> +extern int is_ada_operator (const char *string);
> +
> +/* Find an instance of the character C in the string S that is outside
> +   of all parenthesis pairs, single-quoted strings, and double-quoted
> +   strings.  Also, ignore the char within a template name, like a ','
> +   within foo<int, int>.  */
> +
> +extern const char *find_toplevel_char (const char *s, char c);
> +
> +/* Does P represent one of the keywords?  If so, return
> +   the keyword.  If not, return NULL.  */
> +
> +extern const char *linespec_lexer_lex_keyword (const char *p);
> +
>  /* 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..4e8c3b5 100644
> --- a/gdb/location.c
> +++ b/gdb/location.c
> @@ -442,6 +442,202 @@ 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)
> +	    {
> +	      volatile struct gdb_exception e;
> +
> +	      TRY_CATCH (e, RETURN_MASK_ERROR)
> +		{
> +		  EL_EXPLICIT (location)->line_offset
> +		    = linespec_parse_line_offset (oarg);
> +		}
> +
> +	      xfree (oarg);
> +	      if (e.reason < 0 && !dont_throw)
> +		throw_exception (e);
> +	      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 +670,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..2bb9291
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/cpexplicit.exp
> @@ -0,0 +1,104 @@
> +# Copyright 2012-2013 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tests for explicit linespecs
> +
> +if {[skip_cplus_tests]} {
> +    unsupported "skipping C++ tests"
> +    return
> +}
> +
> +standard_testfile .cc
> +set exefile $testfile
> +
> +if {[prepare_for_testing $testfile $exefile $srcfile \
> +	 {c++ debug nowarnings}]} {
> +    return -1
> +}
> +
> +# Test the given (explicit) LINESPEC which should cause gdb to break
> +# at LOCATION.
> +proc test_breakpoint {linespec location} {
> +
> +    # Delete all breakpoints, set a new breakpoint at LINESPEC,
> +    # and attempt to run to it.
> +    delete_breakpoints
> +    gdb_breakpoint $linespec
> +    gdb_continue_to_breakpoint $linespec $location
> +}
> +
> +# Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
> +# to stop at LOCATION.
> +proc add {thearray linespec location} {
> +    upvar $thearray ar
> +
> +    lappend ar(linespecs) $linespec
> +    lappend ar(locations) $location
> +}
> +
> +# Make sure variables are not already in use
> +unset -nocomplain lineno location linespecs
> +
> +# Some locations used in this test
> +set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
> +set lineno(entry) [gdb_get_line_number "entry location" $srcfile]
> +set lineno(top) [gdb_get_line_number "top location" $srcfile]
> +set lineno(operator) [gdb_get_line_number "operator location" $srcfile]
> +foreach v [array names lineno] {
> +    set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
> +}
> +
> +# A list of explicit linespecs and the corresponding location
> +set linespecs(linespecs) {}
> +set linespecs(location) {}
> +
> +add linespecs "-source $srcfile -function myclass::myfunction" $location(normal)
> +add linespecs "-source $srcfile -function myclass::myfunction -label top" \
> +    $location(top)
> +
> +# This isn't implemented yet; -line is silently ignored.
> +add linespecs \
> +    "-source $srcfile -function myclass::myfunction -label top -line 3" \
> +    $location(top)
> +add linespecs "-source $srcfile -line $lineno(top)" $location(top)
> +add linespecs "-function myclass::myfunction" $location(normal)
> +add linespecs "-function myclass::myfunction -label top" $location(top)
> +
> +# These are also not yet supported; -line is silently ignored.
> +add linespecs "-function myclass::myfunction -line 3" $location(normal)
> +add linespecs "-function myclass::myfunction -label top -line 3" $location(top)
> +add linespecs "-line 3" $location(normal)
> +add linespecs "-function myclass::operator," $location(operator)
> +add linespecs "-function 'myclass::operator,'" $location(operator)
> +add linespecs "-function \"myclass::operator,\"" $location(operator)
> +
> +# Fire up gdb.
> +if {![runto_main]} {
> +    return -1
> +}
> +
> +# Test explicit linespecs, with and without conditions.
> +foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
> +    # Test the linespec
> +    test_breakpoint $linespec $loc_pattern
> +}
> +
> +# Special (orphaned) dprintf cases.
> +gdb_test "dprintf -function myclass::operator,,\"hello\"" \
> +    "Dprintf .*$srcfile, line $lineno(operator)\\."
> +gdb_test "dprintf -function 'myclass::operator,',\"hello\"" \
> +    "Dprintf .*$srcfile, line $lineno(operator)\\."
> +gdb_test "dprintf -function \"myclass::operator,\",\"hello\"" \
> +    "Dprintf .*$srcfile, line $lineno(operator)\\."
> diff --git a/gdb/testsuite/gdb.linespec/explicit.c b/gdb/testsuite/gdb.linespec/explicit.c
> new file mode 100644
> index 0000000..4e1c635
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit.c
> @@ -0,0 +1,56 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2012-2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +extern int myfunction2 (int arg);
> +
> +static int
> +myfunction (int arg)
> +{
> +  int i, j, r;
> +
> +  j = 0; /* myfunction location */
> +  r = arg;
> +
> + top:
> +  ++j;  /* top location */
> +
> +  if (j == 10)
> +    goto done;
> +
> +  for (i = 0; i < 10; ++i)
> +    {
> +      r += i;
> +      if (j % 2)
> +	goto top;
> +    }
> +
> + done:
> +  return r;
> +}
> +
> +int
> +main (void)
> +{
> +  int i, j;
> +
> +  /* Call the test function repeatedly, enough times for all our tests
> +     without running forever if something goes wrong.  */
> +  for (i = 0, j = 0; i < 1000; ++i)
> +    j += myfunction (0);
> +
> +  return myfunction2 (j);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
> new file mode 100644
> index 0000000..854e16f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit.exp
> @@ -0,0 +1,366 @@
> +# Copyright 2012-2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tests for explicit locations
> +
> +standard_testfile explicit.c explicit2.c 3explicit.c
> +set exefile $testfile
> +
> +if {[prepare_for_testing $testfile $exefile \
> +	 [list $srcfile $srcfile2 $srcfile3] {debug nowarnings}]} {
> +    return -1
> +}
> +
> +# Test the given (explicit) LINESPEC which should cause gdb to break
> +# at LOCATION.
> +proc test_breakpoint {linespec location} {
> +
> +    set testname "set breakpoint at \"$linespec\""
> +    # Delete all breakpoints, set a new breakpoint at LINESPEC,
> +    # and attempt to run to it.
> +    delete_breakpoints
> +    if {[gdb_breakpoint $linespec]} {
> +	pass $testname
> +	send_log "\nexpecting locpattern \"$location\"\n"
> +	gdb_continue_to_breakpoint $linespec $location
> +    } else {
> +	fail $testname
> +    }
> +}
> +
> +# Add the given LINESPEC to the array named in THEARRAY.  GDB is expected
> +# to stop at LOCATION.
> +proc add {thearray linespec location} {
> +    upvar $thearray ar
> +
> +    lappend ar(linespecs) $linespec
> +    lappend ar(locations) $location
> +}
> +
> +# Make sure variables are not already in use
> +unset -nocomplain all_arguments lineno location linespecs
> +
> +# A list of all explicit linespec arguments.
> +set all_arguments {"source" "function" "label" "line"}
> +
> +# Some locations used in this test
> +set lineno(normal) [gdb_get_line_number "myfunction location" $srcfile]
> +set lineno(top) [gdb_get_line_number "top location" $srcfile]
> +foreach v [array names lineno] {
> +    set location($v) ".*[string_to_regexp "$srcfile:$lineno($v)"].*"
> +}
> +
> +# A list of explicit locations and the corresponding location.
> +set linespecs(linespecs) {}
> +set linespecs(location) {}
> +
> +add linespecs "-source $srcfile -function myfunction" $location(normal)
> +add linespecs "-source $srcfile -function myfunction -label top" \
> +    $location(top)
> +
> +# This isn't implemented yet; -line is silently ignored.
> +add linespecs "-source $srcfile -function myfunction -label top -line 3" \
> +    $location(top)
> +add linespecs "-source $srcfile -line $lineno(top)" $location(top)
> +add linespecs "-function myfunction" $location(normal)
> +add linespecs "-function myfunction -label top" $location(top)
> +
> +# These are also not yet supported; -line is silently ignored.
> +add linespecs "-function myfunction -line 3" $location(normal)
> +add linespecs "-function myfunction -label top -line 3" $location(top)
> +add linespecs "-line 3" $location(normal)
> +
> +# Test that static tracepoints on marker ID are not interpreted
> +# as an erroneous explicit option.
> +gdb_test "strace -m gdbfoobarbaz" "You can't do that.*"
> +
> +# Fire up gdb.
> +if {![runto_main]} {
> +    return -1
> +}
> +
> +# Simple error tests (many more are tested in ls-err.exp)
> +foreach arg $all_arguments {
> +    # Test missing argument
> +    gdb_test "break -$arg" [string_to_regexp "missing argument for \"-$arg\""]
> +
> +    # Test abbreviations
> +    set short [string range $arg 0 3]
> +    gdb_test "break -$short" \
> +	[string_to_regexp "missing argument for \"-$short\""]
> +}
> +
> +# Test invalid arguments
> +foreach arg {"-foo" "-foo bar" "-function myfunction -foo" \
> +		 "-function -myfunction -foo bar"} {
> +    gdb_test "break $arg" \
> +	[string_to_regexp "invalid explicit location argument, \"-foo\""]
> +}
> +
> +# Test explicit locations, with and without conditions.
> +# For these tests, it is easiest to turn of pending breakpoint.
> +gdb_test_no_output "set breakpoint pending off" "turn off pending breakpoints"
> +
> +foreach linespec $linespecs(linespecs) loc_pattern $linespecs(locations) {
> +
> +    # Test the linespec
> +    test_breakpoint $linespec $loc_pattern
> +
> +    # Test with a valid condition
> +    delete_breakpoints
> +    set tst "set breakpoint at \"$linespec\" with valid condition"
> +    if {[gdb_breakpoint "$linespec if arg == 0"]} {
> +	pass $tst
> +
> +	gdb_test "info break" ".*stop only if arg == 0.*" \
> +	    "info break of conditional breakpoint at \"$linespec\""
> +    } else {
> +	fail $tst
> +    }
> +
> +    # Test with invalid condition
> +    gdb_test "break $linespec if foofoofoo == 1" \
> +	".*No symbol \"foofoofoo\" in current context.*" \
> +	"set breakpoint at \"$linespec\" with invalid condition"
> +
> +    # Test with thread
> +    delete_breakpoints
> +    gdb_test "break $linespec thread 123" "Unknown thread 123."
> +}
> +
> +# Test the explicit location completer
> +foreach abbrev {"fun" "so" "lab" "li"} \
> +    full {"function" "source" "label" "line"} {
> +    set tst "complete 'break -$abbrev'"
> +    send_gdb "break -${abbrev}\t"
> +    gdb_test_multiple "" $tst {
> +	"break -$full " {
> +	    send_gdb "\n"
> +	    gdb_test_multiple "" $tst {
> +		-re "missing argument for \"-$full\".*$gdb_prompt " {
> +		    pass $tst
> +		}
> +	    }
> +	}
> +    }
> +}
> +
> +set tst "complete unique function name"
> +send_gdb "break -function mai\t"
> +gdb_test_multiple "" $tst {
> +    "break -function mai\\\x07n" {
> +	send_gdb "\n"
> +	gdb_test "" ".*Breakpoint \[0-9\]+.*" $tst
> +	gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +    }
> +}
> +
> +set tst "complete non-unique function name"
> +send_gdb "break -function myfunc\t"
> +gdb_test_multiple "" $tst {
> +    "break -function myfunc\\\x07tion" {
> +	send_gdb "\t\t"
> +	gdb_test_multiple "" $tst {
> +	    -re "\\\x07\r\nmyfunction\[ \t\]+myfunction2\[ \t\]+myfunction3\[ \t\]+myfunction4\[ \t\]+\r\n$gdb_prompt " {
> +		gdb_test "2" ".*Breakpoint \[0-9\]+.*" $tst
> +		gdb_test_no_output "delete \$bpnum" "delete $tst breakpoint"
> +	    }
> +	}
> +    }
> +}
> +
> +set tst "complete non-existant function name"
> +send_gdb "break -function foo\t"
> +gdb_test_multiple "" $tst {
> +    "break -function foo\\\x07" {
> +	send_gdb "\t\t"
> +	gdb_test_multiple "" $tst {
> +	    -re "\\\x07\\\x07" {
> +		send_gdb "\n"
> +		gdb_test "" {Function "foo" not defined.} $tst
> +	    }
> +	}
> +    }
> +}
> +
> +set tst "complete unique file name"
> +send_gdb "break -source 3ex\t"
> +gdb_test_multiple "" $tst {
> +    "break -source 3explicit.c " {
> +	send_gdb "\n"
> +	gdb_test "" \
> +	    {Source filename requires function, label, or line offset.} $tst
> +    }
> +}
> +
> +set tst "complete non-unique file name"
> +send_gdb "break -source exp\t"
> +gdb_test_multiple "" $tst {
> +    "break -source exp\\\x07licit" {
> +	send_gdb "\t\t"
> +	gdb_test_multiple "" $tst {
> +	    -re "\\\x07\r\nexplicit.c\[ \t\]+explicit2.c\[ \t\]+\r\n$gdb_prompt" {
> +		send_gdb "\n"
> +		gdb_test "" \
> +		    {Source filename requires function, label, or line offset.} \
> +		    $tst
> +	    }
> +	}
> +    }
> +
> +    "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
> +    }
> +}
> +
> +unset -nocomplain lineno tst
> diff --git a/gdb/testsuite/gdb.linespec/explicit2.c b/gdb/testsuite/gdb.linespec/explicit2.c
> new file mode 100644
> index 0000000..218cccb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/explicit2.c
> @@ -0,0 +1,24 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2013 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +extern int myfunction3 (int arg);
> +
> +int
> +myfunction2 (int arg)
> +{
> +  return myfunction3 (arg);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/ls-errs.exp b/gdb/testsuite/gdb.linespec/ls-errs.exp
> index 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] 25+ messages in thread

* Re: [PATCH v3 8/9] Explicit locations: MI support for explicit locations
  2015-02-17 22:07 ` [PATCH v3 8/9] Explicit locations: MI support for explicit locations Keith Seitz
@ 2015-03-01 21:15   ` Doug Evans
  0 siblings, 0 replies; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:15 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] 25+ messages in thread

* Re: [PATCH v3 9/9] Explicit locations: documentation updates
  2015-02-17 22:50 ` [PATCH v3 9/9] Explicit locations: documentation updates Keith Seitz
@ 2015-03-01 21:25   ` Doug Evans
  2015-05-07 17:07     ` Keith Seitz
  0 siblings, 1 reply; 25+ messages in thread
From: Doug Evans @ 2015-03-01 21:25 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz <keiths@redhat.com> writes:
> 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.

Hi.
A few comments inline.
grep for ^====

> diff --git a/gdb/NEWS b/gdb/NEWS
> index 624f508..0b4581e 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -193,6 +193,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 046219b..a902b7b 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -16114,25 +16114,44 @@ all_tracepoints (void)
>  }
>  
>  \f
> +/* This help string is used to consolidate all the help string for specifying
> +   locations used by several commands.  */

====
A blank line here would help readability (for this reader).

> +#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) or `-probe-stap' (for a SystemTap 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\
> @@ -16627,20 +16646,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);
>  
> @@ -16833,7 +16849,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."));
> @@ -16845,31 +16861,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\
> @@ -17021,11 +17033,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 d1f22de..bce6482 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -6016,9 +6016,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.
>  
> @@ -7444,21 +7444,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}.
> @@ -7483,11 +7483,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}
> @@ -7526,25 +7531,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{Explict locations} allow the user to directly specify the source

====
Typo. Explicit.

> +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
> @@ -7569,22 +7642,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
> @@ -7902,9 +7959,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
>  
> @@ -7922,7 +7979,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.
> @@ -8032,7 +8089,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}.
> @@ -11630,9 +11687,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
> @@ -11937,12 +11994,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
> @@ -15822,14 +15878,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
> @@ -16757,20 +16813,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
> @@ -26474,6 +26527,7 @@ N.A.
>  
>  @subheading The @code{-break-insert} Command
>  @findex -break-insert
> +@anchor{-break-insert}
>  
>  @subsubheading Synopsis
>  
> @@ -26486,16 +26540,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
> @@ -26587,17 +26660,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] 25+ messages in thread

* Re: [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API
  2015-03-01 20:14   ` Doug Evans
@ 2015-05-07 16:59     ` Keith Seitz
  0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2015-05-07 16:59 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 03/01/2015 12:14 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>>
>> +/* 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 *p, *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.keyword_ok = 1;
>
> ====
> parser.keyword_ok = 0; ?

Nope. Not in this case. We need to stop lexing when we find a keyword.
Otherwise, default locations will break. From signest.exp:

(gdb) break if 0
Function "if 0" not defined.
Make breakpoint pending on future shared library load? (y or [n])

>> +  orig = p = *stringp;
>> +  parser.lexer.stream = &p;
>> +
>> +  TRY_CATCH (e, RETURN_MASK_ERROR)
>> +    {
>> +      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 == '*')
>
> ====
> Will this mis-parse an address appearing after the first token?
> [IOW, *address must be the first token, right?]

That's right. I have made no attempt to change the current behavior. But
it doesn't really matter in this context. The chunk dealing with address
locations is removed from this function in the
explicit-address-locations patch. [It causes no regressions in the test
suite, so buildbot should not report any, either.]

>> +	    {
>> +	      const char *arg, *orig;
>> +
>> +	      orig = arg = *stringp;
>> +	      (void) linespec_expression_to_pc (&arg);
>> +	      PARSER_STREAM (&parser) += arg - orig;
>
> ====
> How about: PARSER_STREAM (&parser) = arg; ?

Sure. [NOTE: This disappears in subsequent patch.]

>> +	      break;
>> +	    }
>> +
>> +	  token = linespec_lexer_consume_token (&parser);
>> +
>> +	  /* Keywords are okay after the first token.  */
>> +	  parser.keyword_ok = 1;
>> +	}
>> +      while (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD);
>> +    }
>> +
>> +  *stringp += PARSER_STREAM (&parser) - orig;
>
> ====
> Similary, how about: *stringp = PARSER_STREAM (&parser); ?
>

Unfortunately, we cannot do this. PARSER_STREAM is const, stringp is
not. Well, we probably could do this, but it would require
constification of a lot of other functions/files. I'd be happy to
investigate that as a follow-up patch.

I'll have a new series posted here in a bit.

Keith

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

* Re: [PATCH v3 3/9] Explicit locations: use new location API
  2015-03-01 20:54   ` Doug Evans
@ 2015-05-07 17:03     ` Keith Seitz
  0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2015-05-07 17:03 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 03/01/2015 12:53 PM, Doug Evans wrote:
> Keith Seitz<keiths@redhat.com>  writes:
>
>> >-/* 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.
>> >+/* 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_ARG
>> >+   parameter.
>> >+
>> >+   If PARSE_ARG 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_ARG is non-zero and LOCATION is a linespec location,
>> >+   this function will attempt to extract the location, condition, thread,
>> >+   and extra string from the linespec stored in LOCATION.
>> >+   For non-linespec locations EXTRA_STRING is parsed for condition, thread,
>> >+   and extra string.
>> >+
>> >     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.  */
>> >+   from the internal breakpoint count.
>> >+
>> >+   Returns true if any breakpoint was created; false otherwise.  */
>> >
>> >  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,
> ====
> Rename parse_arg to parse_location or parse_extra?
> ["parse_arg" made sense when "arg" was a parameter, but it's confusing now]

Sure. I've picked parse_extra and updated the comment. That also works
well with your next comment:

>> >@@ -10082,6 +10130,8 @@ create_breakpoint (struct gdbarch *gdbarch,
>> >       breakpoint.  */
>> >    if (!pending)
>> >      {
>> >+      char *arg = extra_string;
> ====
> I gather having "arg" is here to minimize changes, but it reduces
> readability a bit.

I've simply removed the local variable `arg' and passed extra_string to
find_condition_and_thread.

>> >@@ -10159,7 +10222,15 @@ create_breakpoint (struct gdbarch *gdbarch,
>> >  	    }
>> >  	  b->cond_string = cond_string;
>> >  	}
>> >-      b->extra_string = NULL;
>> >+
>> >+      /* Make a private copy of extra_string for the breakpoint.  */
>> >+      if (extra_string != NULL)
>> >+	{
>> >+	  b->extra_string = xstrdup (extra_string);
>> >+	  make_cleanup (xfree, b->extra_string);
> ====
> This cleanup is odd. I would have expected a cleanup for "b" to
> completely clean itself up. However, it looks like no cleanup for "b"
> is ever created. So that's an existing bug which I wouldn't impose
> on this patchset to fix, but OTOH this cleanup still feels wrong.

I've rewritten/rearranged this a little bit so that it more closely
mimics what is done with cond_string immediately before it. [And, you're
right -- `b' doesn't get "cleaned up" in the way you'd expect. It took
me a couple of read-throughs to figure this out, too.]

> Also, the docs of extra_string in breakpoint.h are lacking.

Docs for create_breakpoint don't even exist in breakpoint.h! :-) I've
moved them there.

> It's not something that has to be fixed with this patchset,
> but I'm having to dig too deep to figure out how extra_string
> is different from cond_string. Can I trouble you to clarify things?

I have made an attempt at it. [It turns out that this needed rewriting
anyway -- I apparently forgot to fully update the comment on this last
revision.]

>> >@@ -10206,16 +10277,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)
> ====
> Extra space before &&.
>

Fixed.

>> >@@ -14582,21 +14691,37 @@ 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)
>> >  	{
>> >-	  char *cond_string, *extra_string;
>> >-	  int thread, task;
>> >+	  const char *s = b->extra_string;
>> >
>> >-	  find_condition_and_thread (s, sals.sals[0].pc,
>> >-				     &cond_string, &thread, &task,
>> >-				     &extra_string);
>> >-	  if (cond_string)
>> >-	    b->cond_string = cond_string;
>> >-	  b->thread = thread;
>> >-	  b->task = task;
>> >-	  if (extra_string)
>> >-	    b->extra_string = extra_string;
>> >-	  b->condition_not_parsed = 0;
>> >+	  if (s != NULL && *s != '\0')
> ====
> If we have a rule that b->extra_string is never "" (only NULL) then
> we can simplify this, and even remove this extra nested "if".
> E.g., just have
>
> +      if (b->condition_not_parsed && b->extra_string != NULL)
>

Yes, good catch!

>> >@@ -433,10 +434,9 @@ linespec_lexer_lex_keyword (const char *p)
>> >  	  int len = strlen (linespec_keywords[i]);
>> >
>> >  	  /* If P begins with one of the keywords and the next
>> >-	     character is not a valid identifier character,
>> >-	     we have found a keyword.  */
>> >+	     character is whitespace, we have found a keyword.  */
>> >  	  if (strncmp (p, linespec_keywords[i], len) == 0
>> >-	      && !(isalnum (p[len]) || p[len] == '_'))
>> >+	      && isspace (p[len]))
> ====
> I think I'm ok with this change, but it seems separate from this patchset.
> Submit it separately?

Some time ago, I committed a more complete patch for this.

>> >@@ -1765,21 +1765,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);
> ====
> No need to make this change now (assuming it's doable),
> but I'm curious if the parser needs to modify its argument
> or whether we can pass a const char * and remove the ASTRDUP here
> (and elsewhere).
>

s/its argument/its state/ ? Otherwise I'm not entirely sure what you
mean. The linespec parser takes all const arguments already
(parse_linespec [now] takes const char *, decode_line* take const struct
event_location *).

I could change canonicalize_linespec to take the canonical location
instead of the entire parser state, though, yes, that's doable, but it
still needs to be mutable.

>> >@@ -1999,8 +2001,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 = ASTRDUP (core_addr_to_string (pc));
> ====
> The leading '*' got dropped.
> I can imagine this is just temporary anyway, as a later patch
> (address locations) redoes this again.
> I'm ok with leaving it as is, but I'd be remiss if I didn't
> point it out.

Yes, it did drop the '*'! For completeness, I've put it back, even if
temporary.

Keith

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

* Re: [PATCH v3 4/9] Explicit locations: introduce address locations
  2015-03-01 21:03   ` Doug Evans
@ 2015-05-07 17:05     ` Keith Seitz
  0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2015-05-07 17:05 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 03/01/2015 01:02 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>> +/* 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);
>> +
>> +  if (self->canonical != NULL)
>> +    self->canonical->location = new_address_location (address);
>
> ====
> Modifying self->canonical->location is an undocumented side-effect.
> Can you augment the function comment to document and explain this?

In general, all of the convert_*_location_to_sals functions will
canonicalize the location into linespec_state.canonical.

Address locations are, though, completely specified, unlike some
linespecs/explicit locations, where we might have to "fill-in" some
missing bits, e.g., "b 30" -> "30" -> "sourcefile.c:30".

In that vein, I am simply going to remove this. It is not needed anymore.

Keith


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

* Re: [PATCH v3 7/9] Explicit locations: add UI features for CLI
  2015-03-01 21:14   ` Doug Evans
@ 2015-05-07 17:07     ` Keith Seitz
  0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2015-05-07 17:07 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 03/01/2015 01:14 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>
>> +/* 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)
>> +{
[snip]
>> +    case MATCH_LABEL:
>> +      /* Not supported.  */
>> +      break;
>> +
>> +    default:
>> +      gdb_assert_not_reached (_("unhandled explicit_location_match_type"));
>
> ====
> No need for _() here.

Fixed.

>
>> +    }
>> +
>> +  return matches;
>> +}
>> +
>> +/* A convenience macro to (safely) back up P to the previous
>> +   word.  */
>
> ====
> This comment can be just one line.
> I'd rather a comment run past the soft limit (and still fit within the
> hard limit) than use an extra line just for one word.
>

Fixed.

>> +
>> +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;
>> +}
>> +
>
> ====
> Missing function comment.
>

Doh! Added.

>> +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.  */
>
> ====
> I couldn't get "b -<tab><tab>" to work. Can do?
>

Unfortunately, "-" is a valid linespec, so no, "b -<TAB><TAB>" will not
do anything.

>> +
>> +      /* Skip over the '-'.  */
>> +      ++p;
>> +
>> +      if (strncmp (p, "source", len) == 0)
[snip]
>> +      /* Now gather matches  */
>> +      matches = collect_explicit_location_matches (location, what, new_word);
>
> ====
> Something's not right here as "b -f <tab>" segv's because new_word is NULL.
>

Yes, indeed. The struct explicit_location uses NULL for unspecified
parameters, and these consequently get passed as new_word to
collect_explicit_location_matches, which passes it to GDB's completion
functions, which do NOT like NULL.

I've fixed this and added tests for them. Thank you for catching this
serious bug.

Keith

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

* Re: [PATCH v3 9/9] Explicit locations: documentation updates
  2015-03-01 21:25   ` Doug Evans
@ 2015-05-07 17:07     ` Keith Seitz
  0 siblings, 0 replies; 25+ messages in thread
From: Keith Seitz @ 2015-05-07 17:07 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On 03/01/2015 01:24 PM, Doug Evans wrote:
> Keith Seitz <keiths@redhat.com> writes:
>
>> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
>> index 046219b..a902b7b 100644
>> --- a/gdb/breakpoint.c
>> +++ b/gdb/breakpoint.c
>> @@ -16114,25 +16114,44 @@ all_tracepoints (void)
>>   }
>>
>>   \f
>> +/* This help string is used to consolidate all the help string for specifying
>> +   locations used by several commands.  */
>
> ====
> A blank line here would help readability (for this reader).
>

Added.

>> +@subsection Explicit Locations
>> +@cindex explicit locations
>> +@anchor{Explicit Locations}
>> +
>> +@dfn{Explict locations} allow the user to directly specify the source
>
> ====
> Typo. Explicit.
>

Fixed -- good catch!

Keith

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

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

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-17 22:06 [PATCH v3 0/9] Locations API Keith Seitz
2015-02-17 22:06 ` [PATCH v3 1/9] Explicit locations: rename "address string"/"addr_string" to "location" Keith Seitz
2015-03-01 20:08   ` Doug Evans
2015-02-17 22:06 ` [PATCH v3 4/9] Explicit locations: introduce address locations Keith Seitz
2015-03-01 21:03   ` Doug Evans
2015-05-07 17:05     ` Keith Seitz
2015-02-17 22:06 ` [PATCH v3 2/9] Explicit locations: introduce new struct event_location-based API Keith Seitz
2015-03-01 20:14   ` Doug Evans
2015-05-07 16:59     ` Keith Seitz
2015-02-17 22:07 ` [PATCH v3 8/9] Explicit locations: MI support for explicit locations Keith Seitz
2015-03-01 21:15   ` Doug Evans
2015-02-17 22:07 ` [PATCH v3 6/9] Explicit locations: introduce " Keith Seitz
2015-03-01 21:04   ` Doug Evans
2015-02-17 22:07 ` [PATCH v3 5/9] Explicit locations: introduce probe locations Keith Seitz
2015-03-01 21:03   ` Doug Evans
2015-02-17 22:07 ` [PATCH v3 7/9] Explicit locations: add UI features for CLI Keith Seitz
2015-03-01 21:14   ` Doug Evans
2015-05-07 17:07     ` Keith Seitz
2015-02-17 22:07 ` [PATCH v3 3/9] Explicit locations: use new location API Keith Seitz
2015-03-01 20:54   ` Doug Evans
2015-05-07 17:03     ` Keith Seitz
2015-02-17 22:50 ` [PATCH v3 9/9] Explicit locations: documentation updates Keith Seitz
2015-03-01 21:25   ` Doug Evans
2015-05-07 17:07     ` Keith Seitz
2015-02-23  4:17 ` [PATCH v3 0/9] Locations API Doug Evans

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).