public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFA 6/9] Explicit locations v2 - Add explicit locations
@ 2014-05-08 18:02 Keith Seitz
  2014-05-30 18:19 ` Keith Seitz
  0 siblings, 1 reply; 4+ messages in thread
From: Keith Seitz @ 2014-05-08 18:02 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml

[-- Attachment #1: Type: text/plain, Size: 2014 bytes --]

Hi,

This patch finally introduces new features/functionality by adding 
support for explicit locations. Explicit locations are introduced 
internally only in this patch. Users cannot do anything with them until 
the next patch.

Like the previous two patches introducing new location types, this patch 
also converts any existing hard-coded linespec locations into explicit form.

Keith

ChangeLog
2014-05-08  Keith Seitz  <keiths@redhat.com>

	* breakpoint.c (create_overlay_breakpoint): Convert linespec
	into explicit location.
	(create_longjmp_master_breakpoint): Likewise.
	(create_std_terminate_master_breakpoint): Likewise.
	(create_exception_master_breakpoint): Likewise.
	(create_breakpoint): Update the SAVE_SPEC for explicit locations.
	(update_static_tracepoint): Convert linespec into explicit location.
	(location_to_sals): Save the SAVE_SPEC for pending breakpoints
	which were resolved.
	* linespec.c (enum offset_relative_sign): Move to location.h.
	(struct line_offset): Likewise.
	(undefined_label_error): New function.
	(source_file_not_found_error): New function.
	(linespec_parse_basic): Use undefined_label_error.
	(canonicalize_linespec): Convert canonical linespec into explicit
	location.
	(convert_explicit_location_to_sals): New function.
	(event_location_to_sals): Handle explicit locations.
	(symtabs_from_filename): Use source_file_not_found_error.
	* location.c (initialize_explicit_location): New function.
	(initialize_event_location): Initialize explicit locations.
	(copy_event_location): Handle explicit locations.
	(delete_event_location): Likewise.
	(event_location_to_string): 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 EVENT_LOCATION_EXPLICIT.
	(struct explicit_location): New structure.
	(struct event_location.u) <explicit>: New member.
	(EVENT_LOCATION_EXPLICIT): Define accessor macro.
	(initialize_explicit_location): Declare.

[-- Attachment #2: explicit-explicit-locations.patch --]
[-- Type: text/x-patch, Size: 17628 bytes --]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index fdf7c10..74c40a4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3305,8 +3305,9 @@ create_overlay_event_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_overlay_event,
 				      &internal_breakpoint_ops);
-      b->location = new_event_location (EVENT_LOCATION_LINESPEC);
-      EVENT_LOCATION_LINESPEC (b->location) = xstrdup (func_name);
+      b->location = new_event_location (EVENT_LOCATION_EXPLICIT);
+      EVENT_LOCATION_EXPLICIT (b->location)->function_name
+	= xstrdup (func_name);
 
       if (overlay_debugging == ovly_auto)
         {
@@ -3426,8 +3427,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);
-	  b->location = new_event_location (EVENT_LOCATION_LINESPEC);
-	  EVENT_LOCATION_LINESPEC (b->location) = xstrdup (func_name);
+	  b->location = new_event_location (EVENT_LOCATION_EXPLICIT);
+	  EVENT_LOCATION_EXPLICIT (b->location)->function_name
+	    = xstrdup (func_name);
 	  b->enable_state = bp_disabled;
 	}
     }
@@ -3483,8 +3485,9 @@ create_std_terminate_master_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_std_terminate_master,
 				      &internal_breakpoint_ops);
-      b->location = new_event_location (EVENT_LOCATION_LINESPEC);
-      EVENT_LOCATION_LINESPEC (b->location) = xstrdup (func_name);
+      b->location = new_event_location (EVENT_LOCATION_EXPLICIT);
+      EVENT_LOCATION_EXPLICIT (b->location)->function_name
+	= xstrdup (func_name);
       b->enable_state = bp_disabled;
     }
   }
@@ -3589,8 +3592,9 @@ create_exception_master_breakpoint (void)
 						 &current_target);
       b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 				      &internal_breakpoint_ops);
-      b->location = new_event_location (EVENT_LOCATION_LINESPEC);
-      EVENT_LOCATION_LINESPEC (b->location) = xstrdup (func_name);
+      b->location = new_event_location (EVENT_LOCATION_EXPLICIT);
+      EVENT_LOCATION_EXPLICIT (b->location)->function_name
+	= xstrdup (func_name);
       b->enable_state = bp_disabled;
     }
 
@@ -10015,7 +10019,17 @@ create_breakpoint (struct gdbarch *gdbarch,
       /* If the location has a string representation,
 	 save it to the breakpoint's location save spec, since this
 	 may be used to save the breakpoint to a file.  */
-      if (EVENT_LOCATION_SAVE_SPEC (b->location) == NULL
+      if (EVENT_LOCATION_TYPE (b->location) == EVENT_LOCATION_EXPLICIT)
+	{
+	  char *old = EVENT_LOCATION_SAVE_SPEC (b->location);
+
+	  EVENT_LOCATION_SAVE_SPEC (b->location)
+	    = xstrprintf ("%s%s%s", old,
+			  (extra_string == NULL ? "" : " "),
+			  (extra_string == NULL ? "" : extra_string));
+	  xfree (old);
+	}
+      else if (EVENT_LOCATION_SAVE_SPEC (b->location) == NULL
 	       && event_location_to_string (b->location) != NULL)
 	{
 	  EVENT_LOCATION_SAVE_SPEC (b->location)
@@ -14272,11 +14286,11 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 	  b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
 
 	  delete_event_location (b->location);
-	  b->location = new_event_location (EVENT_LOCATION_LINESPEC);
-	  EVENT_LOCATION_LINESPEC (b->location)
-	    = xstrprintf ("%s:%d",
-			  symtab_to_filename_for_display (sal2.symtab),
-			  b->loc->line_number);
+	  b->location = new_event_location (EVENT_LOCATION_EXPLICIT);
+	  EVENT_LOCATION_EXPLICIT (b->location)->source_filename
+	    = xstrdup (symtab_to_filename_for_display (sal2.symtab));
+	  EVENT_LOCATION_EXPLICIT (b->location)->line_offset.offset
+	    = b->loc->line_number;
 
 	  /* Might be nice to check if function changed, and warn if
 	     so.  */
@@ -14528,7 +14542,14 @@ location_to_sals (struct breakpoint *b, struct event_location *location,
 		  char *p, *str;
 		  char *old = EVENT_LOCATION_SAVE_SPEC (location);
 
-		  len = orig - prev;
+		  if (EVENT_LOCATION_TYPE (location) == EVENT_LOCATION_EXPLICIT)
+		    {
+		      len = strlen (prev);
+		      if (s != NULL)
+			len -= strlen (s);
+		    }
+		  else
+		    len = orig - prev;
 
 		  str = savestring (prev, len);
 		  p = remove_trailing_whitespace (str, str + len);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 069aab6..600773c 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -66,31 +66,6 @@ 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.  */
@@ -1550,6 +1525,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
@@ -1724,9 +1722,8 @@ linespec_parse_basic (linespec_parser *parser)
 	  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_RESULT (parser)->function_name,
+				     name);
 	    }
 
 	  /* Check for a line offset.  */
@@ -1782,17 +1779,22 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
   else
     {
       struct ui_file *buf;
+      struct explicit_location *explicit;
       int need_colon = 0;
 
       buf = mem_fileopen ();
 
+      /* Convert any LINESPEC into EXPLICIT form so that the
+	 parsing that was just done does not need to be repeated.  */
       state->canonical->location
-	= new_event_location (EVENT_LOCATION_LINESPEC);
+	= new_event_location (EVENT_LOCATION_EXPLICIT);
+      explicit = EVENT_LOCATION_EXPLICIT (state->canonical->location);
 
       if (ls->source_filename)
 	{
 	  fputs_unfiltered (ls->source_filename, buf);
 	  need_colon = 1;
+	  explicit->source_filename = xstrdup (ls->source_filename);
 	}
 
       if (ls->function_name)
@@ -1801,6 +1803,7 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 	    fputc_unfiltered (':', buf);
 	  fputs_unfiltered (ls->function_name, buf);
 	  need_colon = 1;
+	  explicit->function_name = xstrdup (ls->function_name);
 	}
 
       if (ls->label_name)
@@ -1819,11 +1822,13 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 	      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;
+	  explicit->label_name = xstrdup (ls->label_name);
 	}
 
       if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
@@ -1835,12 +1840,11 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 			     : (ls->line_offset.sign
 				== LINE_OFFSET_PLUS ? "+" : "-")),
 			    ls->line_offset.offset);
+	  explicit->line_offset = ls->line_offset;
 	}
 
-      EVENT_LOCATION_LINESPEC (state->canonical->location)
-	= ui_file_xstrdup (buf, NULL);
       EVENT_LOCATION_SAVE_SPEC (state->canonical->location)
-	= xstrdup (EVENT_LOCATION_LINESPEC (state->canonical->location));
+	= ui_file_xstrdup (buf, NULL);
       ui_file_delete (buf);
     }
 }
@@ -2126,6 +2130,72 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
   return sals;
 }
 
+/* Convert the explicit location EXPLICIT into SaLs.  */
+
+static struct symtabs_and_lines
+convert_explicit_location_to_sals (struct linespec_state *self,
+				   linespec_p result,
+				   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->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->source_filename);
+
+      result->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->function_name, explicit->label_name);
+
+      result->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->line_offset = explicit->line_offset;
+
+  return convert_linespec_to_sals (self, result);
+}
+
 /* Parse a string that specifies a linespec.
    Pass the address of a char * variable; that variable will be
    advanced over the characters actually parsed.
@@ -2457,6 +2527,13 @@ event_location_to_sals (linespec_parser *parser,
 					    EVENT_LOCATION_ADDRESS (location));
       break;
 
+    case EVENT_LOCATION_EXPLICIT:
+      result
+	= convert_explicit_location_to_sals (PARSER_STATE (parser),
+					     PARSER_RESULT (parser),
+					     EVENT_LOCATION_EXPLICIT (location));
+      break;
+
     case EVENT_LOCATION_PROBE:
       /* Probes are handled by their own decoders.  */
        gdb_assert_not_reached ("attempt to decode probe location");
@@ -3122,7 +3199,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 a64d37c..f52026a 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -28,6 +28,15 @@
 #include <ctype.h>
 #include <string.h>
 
+/* Initialize the given explicit location.  */
+
+void
+initialize_explicit_location (struct explicit_location *explicit)
+{
+  memset (explicit, 0, sizeof (struct explicit_location));
+  explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
+}
+
 /* Initialize the given LOCATION.  */
 
 void
@@ -36,6 +45,8 @@ initialize_event_location (struct event_location *location,
 {
   memset (location, 0, sizeof (struct event_location));
   EVENT_LOCATION_TYPE (location) = type;
+  if (type == EVENT_LOCATION_EXPLICIT)
+    initialize_explicit_location (EVENT_LOCATION_EXPLICIT (location));
 }
 
 /* Create a new location with the given TYPE.  */
@@ -72,6 +83,24 @@ copy_event_location (const struct event_location *src)
       EVENT_LOCATION_ADDRESS (dst) = EVENT_LOCATION_ADDRESS (src);
       break;
 
+    case EVENT_LOCATION_EXPLICIT:
+      if (EVENT_LOCATION_EXPLICIT (src)->source_filename != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->source_filename
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->source_filename);
+
+      if (EVENT_LOCATION_EXPLICIT (src)->function_name != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->function_name
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->function_name);
+
+      if (EVENT_LOCATION_EXPLICIT (src)->label_name != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->label_name
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->label_name);
+
+      EVENT_LOCATION_EXPLICIT (dst)->line_offset
+	= EVENT_LOCATION_EXPLICIT (src)->line_offset;
+      break;
+
+
     case EVENT_LOCATION_PROBE:
       EVENT_LOCATION_PROBE (dst) = xstrdup (EVENT_LOCATION_PROBE (src));
       break;
@@ -105,6 +134,12 @@ delete_event_location (void *data)
 	  /* Nothing to do.  */
 	  break;
 
+	case EVENT_LOCATION_EXPLICIT:
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->source_filename);
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->function_name);
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->label_name);
+	  break;
+
 	case EVENT_LOCATION_PROBE:
 	  xfree (EVENT_LOCATION_PROBE (location));
 	  break;
@@ -133,6 +168,7 @@ event_location_to_string (const struct event_location *location)
       break;
 
     case EVENT_LOCATION_ADDRESS:
+    case EVENT_LOCATION_EXPLICIT:
       result = EVENT_LOCATION_SAVE_SPEC (location);
       break;
 
@@ -211,6 +247,14 @@ event_location_empty_p (const struct event_location *location)
     case EVENT_LOCATION_ADDRESS:
       return 0;
 
+    case EVENT_LOCATION_EXPLICIT:
+      return (EVENT_LOCATION_EXPLICIT (location) == NULL
+	      || (EVENT_LOCATION_EXPLICIT (location)->source_filename == NULL
+		  && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
+		  && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
+		  && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
+		      == LINE_OFFSET_UNKNOWN)));
+
     case EVENT_LOCATION_PROBE:
       return EVENT_LOCATION_PROBE (location) == NULL;
 
diff --git a/gdb/location.h b/gdb/location.h
index b207c87..0d3400a 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -21,6 +21,32 @@
 
 struct language_defn;
 
+/* 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).  */
 
@@ -32,10 +58,35 @@ enum event_location_type
   /* An address in the inferior.  */
   EVENT_LOCATION_ADDRESS,
 
+  /* An explicit location.  */
+  EVENT_LOCATION_EXPLICIT,
+
   /* A probe location.  */
   EVENT_LOCATION_PROBE
 };
 
+/* 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;
+};
+
 /* An event location used to set a stop event in the inferior.
    This structure is an amalgam of the various ways
    to specify a where a stop event should be set.  */
@@ -58,6 +109,10 @@ struct event_location
     /* An address in the inferior.  */
     CORE_ADDR address;
 #define EVENT_LOCATION_ADDRESS(S) ((S)->u.address)
+
+    /* An explicit location.  */
+    struct explicit_location explicit;
+#define EVENT_LOCATION_EXPLICIT(S) (&((S)->u.explicit))
   } u;
 
   /* A string representation of how this location may be
@@ -92,6 +147,10 @@ extern struct event_location *
 extern void initialize_event_location (struct event_location *location,
 				       enum event_location_type type);
 
+/* Initialize the given explicit location.  */
+
+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
    (malloc'd) if an event location was successfully found in *ARGP,

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

* Re: [RFA 6/9] Explicit locations v2 - Add explicit locations
  2014-05-08 18:02 [RFA 6/9] Explicit locations v2 - Add explicit locations Keith Seitz
@ 2014-05-30 18:19 ` Keith Seitz
  2014-08-03  1:50   ` Doug Evans
  0 siblings, 1 reply; 4+ messages in thread
From: Keith Seitz @ 2014-05-30 18:19 UTC (permalink / raw)
  To: gdb-patches@sourceware.org ml

[-- Attachment #1: Type: text/plain, Size: 3776 bytes --]

This is an update to this patch to incorporate changes from reviews of 
earlier patches.

Keith

Changes since last version:
   - remove SAVE_SPEC stuff
   - struct linespec: use struct explicit_location instead of
     all those strings/line_offset.
   - Add PARSER_EXPLICIT and use it where needed
   - No need to "convert linespec to explicit" -- the parser
     now builds an explicit location of the parsed result.
   - move string constructions out of canonicalize_linespec and into
     its own function
   - update comments on grammar of linespecs: expr_spec is now
     no longer considered a linespec.
   - add explicit_to_string_internal and use it to implement
     explicit_location_to_string/explicit_location_to_linespec
   - new_explicit_location
   - remove explicit_to_event_location

ChangeLog
2014-05-29  Keith Seitz  <keiths@redhat.com>

	* breakpoint.c (create_overlay_breakpoint): Convert linespec
	into explicit location.
	(create_longjmp_master_breakpoint): Likewise.
	(create_std_terminate_master_breakpoint): Likewise.
	(create_exception_master_breakpoint): Likewise.
	(create_breakpoint): Update the SAVE_SPEC for explicit locations.
	(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): Use PARSER_EXPLICIT to access the parser's
	explicit location result.
	(convert_linespec_to_sals): `ls' contains an explicit location.
	Update all references.
	(convert_explicit_location_to_sals): New function.
	(linespec_parse_basic): 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 (initialize_explicit_location): New function.
	(initialize_event_location): Initialize explicit locations.
	(copy_event_location): Handle explicit locations.
	(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.
	(delete_event_location): Handle explicit locations.
	(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.
	(struct event_location.u) <explicit>: New member.
	(EVENT_LOCATION_EXPLICIT): Define accessor macro.
	(explicit_location_to_string): Declare.
	(explicit_location_to_linespec): Declare.
	(initialize_explicit_location): Declare.


[-- Attachment #2: explicit-explicit-locations-2.patch --]
[-- Type: text/x-patch, Size: 37703 bytes --]

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 345b104..d8c74c0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3281,6 +3281,7 @@ create_overlay_event_breakpoint (void)
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3305,7 +3306,9 @@ create_overlay_event_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_overlay_event,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
 
       if (overlay_debugging == ovly_auto)
         {
@@ -3402,6 +3405,7 @@ create_longjmp_master_breakpoint (void)
 	  struct breakpoint *b;
 	  const char *func_name;
 	  CORE_ADDR addr;
+	  struct explicit_location explicit;
 
 	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
 	    continue;
@@ -3424,7 +3428,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);
-	  b->location = new_linespec_location (func_name);
+	  initialize_explicit_location (&explicit);
+	  explicit.function_name = ASTRDUP (func_name);
+	  b->location = new_explicit_location (&explicit);
 	  b->enable_state = bp_disabled;
 	}
     }
@@ -3455,6 +3461,7 @@ create_std_terminate_master_breakpoint (void)
     {
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3480,7 +3487,9 @@ create_std_terminate_master_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_std_terminate_master,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
   }
@@ -3504,6 +3513,7 @@ create_exception_master_breakpoint (void)
       struct gdbarch *gdbarch;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3584,7 +3594,9 @@ create_exception_master_breakpoint (void)
 						 &current_target);
       b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
 
@@ -10010,6 +10022,20 @@ create_breakpoint (struct gdbarch *gdbarch,
       init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
       b->location = copy_event_location (location);
 
+      /* If the location has a string representation,
+	 save it to the breakpoint's location string cache, since this
+	 may be used to save the breakpoint to a file.  */
+      if (EVENT_LOCATION_TYPE (b->location) == EXPLICIT_LOCATION)
+	{
+	  char *old = event_location_to_string_const (location);
+
+	  b->location->as_string
+	    = xstrprintf ("%s%s%s", old,
+			  (extra_string == NULL ? "" : " "),
+			  (extra_string == NULL ? "" : extra_string));
+	  xfree (old);
+	}
+
       if (parse_arg)
 	b->cond_string = NULL;
       else
@@ -10022,7 +10048,17 @@ create_breakpoint (struct gdbarch *gdbarch,
 	    }
 	  b->cond_string = cond_string;
 	}
-      b->extra_string = NULL;
+
+      /* For explicit locations, EXTRA_STRING may contain breakpoint
+	 condition information.  Make a private copy of this for the
+	 breakpoint.  */
+      if (extra_string != NULL && *extra_string != '\0')
+	{
+	  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;
@@ -14212,6 +14248,7 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 	  struct symbol *sym;
 	  struct static_tracepoint_marker *tpmarker;
 	  struct ui_out *uiout = current_uiout;
+	  struct explicit_location explicit;
 
 	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
 
@@ -14253,11 +14290,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);
-	  b->location = new_linespec_location (NULL);
-	  EVENT_LOCATION_LINESPEC (b->location)
-	    = xstrprintf ("%s:%d",
-			  symtab_to_filename_for_display (sal2.symtab),
-			  b->loc->line_number);
+	  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 deda86e..f141a86 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -66,73 +66,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.  */
@@ -141,10 +94,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;
 
@@ -197,6 +146,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
@@ -307,6 +259,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,
@@ -1550,6 +1506,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
@@ -1596,7 +1575,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.  */
@@ -1633,7 +1612,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);
     }
@@ -1647,7 +1626,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);
 	}
@@ -1655,14 +1634,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;
 	    }
@@ -1677,7 +1656,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;
 	}
@@ -1697,7 +1676,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);
 
@@ -1717,16 +1696,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.  */
@@ -1744,7 +1722,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);
 
@@ -1761,42 +1739,19 @@ 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, linespec_p ls)
 {
-  struct ui_file *buf;
-  int need_colon = 0;
-
   /* If canonicalization was not requested, no need to do anything.  */
   if (!state->canonical)
     return;
 
-  buf = mem_fileopen ();
-
-  state->canonical->location = new_linespec_location (NULL);
-
-  if (ls->source_filename)
+  if (ls->explicit.label_name)
     {
-      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;
-    }
-
-  if (ls->label_name)
-    {
-      if (need_colon)
-	fputc_unfiltered (':', buf);
-
-      if (ls->function_name == NULL)
+      if (ls->explicit.function_name == NULL)
 	{
 	  struct symbol *s;
 
@@ -1805,29 +1760,22 @@ canonicalize_linespec (struct linespec_state *state, 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);
+	  ls->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 (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);
-    }
+  /* Save everything as an explicit location.  */
+  state->canonical->location = new_explicit_location (&ls->explicit);
 
-  EVENT_LOCATION_LINESPEC (state->canonical->location)
-    = ui_file_xstrdup (buf, NULL);
-  ui_file_delete (buf);
+  /* Save a string representation of this linespec.  */
+  if (state->is_linespec)
+    state->canonical->location->as_string
+      = explicit_location_to_linespec (&ls->explicit);
+  else
+    state->canonical->location->as_string
+      = explicit_location_to_string (&ls->explicit);
 }
 
 /* Given a line offset in LS, construct the relevant SALs.  */
@@ -1867,18 +1815,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;
@@ -1970,9 +1918,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);
@@ -2072,13 +2020,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);
 
@@ -2086,7 +2034,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
@@ -2103,6 +2051,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,
+				   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.
    Pass the address of a char * variable; that variable will be
    advanced over the characters actually parsed.
@@ -2215,13 +2230,13 @@ parse_linespec (linespec_parser *parser, const char **argptr)
       /* 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);
@@ -2257,7 +2272,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
       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);
@@ -2294,7 +2309,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 
   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
@@ -2303,8 +2318,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 	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:
@@ -2342,6 +2357,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.  */
@@ -2356,7 +2372,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);
 }
@@ -2376,10 +2392,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);
@@ -2415,6 +2430,7 @@ event_location_to_sals (linespec_parser *parser,
 	const char *copy, *orig;
 	volatile struct gdb_exception except;
 
+	PARSER_STATE (parser)->is_linespec = 1;
 	TRY_CATCH (except, RETURN_MASK_ERROR)
 	  {
 	    orig = copy = EVENT_LOCATION_LINESPEC (location);
@@ -2433,6 +2449,17 @@ event_location_to_sals (linespec_parser *parser,
 					    EVENT_LOCATION_ADDRESS (location));
       break;
 
+    case EXPLICIT_LOCATION:
+      {
+	struct explicit_location *explicit;
+
+	explicit = EVENT_LOCATION_EXPLICIT (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");
@@ -2691,7 +2718,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
       memcpy (saved_arg, *argptr, new_argptr - *argptr);
       saved_arg[new_argptr - *argptr] = '\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);
@@ -2701,9 +2728,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
 	  self->canonical->pre_expanded = 1;
 	  self->canonical->location = new_linespec_location (NULL);
 
-	  if (ls->source_filename)
+	  if (ls->explicit.source_filename)
 	    EVENT_LOCATION_LINESPEC (self->canonical->location)
-	      = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
+	      = xstrprintf ("%s:%s", ls->explicit.source_filename, saved_arg);
 	  else
 	    EVENT_LOCATION_LINESPEC (self->canonical->location)
 	      = xstrdup (saved_arg);
@@ -3082,7 +3109,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 eafa27d..86d4232 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -28,6 +28,15 @@
 #include <ctype.h>
 #include <string.h>
 
+/* Initialize the given explicit location.  */
+
+void
+initialize_explicit_location (struct explicit_location *explicit)
+{
+  memset (explicit, 0, sizeof (struct explicit_location));
+  explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
+}
+
 /* Initialize the given LOCATION.  */
 
 void
@@ -36,6 +45,8 @@ initialize_event_location (struct event_location *location,
 {
   memset (location, 0, sizeof (struct event_location));
   EVENT_LOCATION_TYPE (location) = type;
+  if (type == EXPLICIT_LOCATION)
+    initialize_explicit_location (EVENT_LOCATION_EXPLICIT (location));
 }
 
 /* Create a new linespec location.  The return result is malloc'd
@@ -82,6 +93,49 @@ new_probe_location (const char *probe)
   return 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.  */
+
+struct event_location *
+new_explicit_location (const struct explicit_location *explicit)
+{
+  struct event_location tmp;
+
+  initialize_event_location (&tmp, EXPLICIT_LOCATION);
+
+  if (explicit != NULL)
+    {
+      if (explicit->source_filename != NULL)
+	{
+	  /* Error check -- we must have one of the other
+	     parameters specified.  */
+	  if (explicit->function_name == NULL
+	      && explicit->label_name == NULL
+	      && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
+	    error (_("Source filename requires function, label, or "
+		     "line offset."));
+
+	  EVENT_LOCATION_EXPLICIT (&tmp)->source_filename
+	    = explicit->source_filename;
+	}
+
+      if (explicit->function_name != NULL)
+	EVENT_LOCATION_EXPLICIT (&tmp)->function_name
+	  = explicit->function_name;
+
+      if (explicit->label_name != NULL)
+	EVENT_LOCATION_EXPLICIT (&tmp)->label_name = explicit->label_name;
+
+      if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+	EVENT_LOCATION_EXPLICIT (&tmp)->line_offset = explicit->line_offset;
+    }
+
+  return copy_event_location (&tmp);
+}
+
 /* Return a copy of the given SRC location.  */
 
 struct event_location *
@@ -104,6 +158,24 @@ copy_event_location (const struct event_location *src)
       EVENT_LOCATION_ADDRESS (dst) = EVENT_LOCATION_ADDRESS (src);
       break;
 
+    case EXPLICIT_LOCATION:
+      if (EVENT_LOCATION_EXPLICIT (src)->source_filename != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->source_filename
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->source_filename);
+
+      if (EVENT_LOCATION_EXPLICIT (src)->function_name != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->function_name
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->function_name);
+
+      if (EVENT_LOCATION_EXPLICIT (src)->label_name != NULL)
+	EVENT_LOCATION_EXPLICIT (dst)->label_name
+	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->label_name);
+
+      EVENT_LOCATION_EXPLICIT (dst)->line_offset
+	= EVENT_LOCATION_EXPLICIT (src)->line_offset;
+      break;
+
+
     case PROBE_LOCATION:
       EVENT_LOCATION_PROBE (dst) = xstrdup (EVENT_LOCATION_PROBE (src));
       break;
@@ -115,6 +187,87 @@ copy_event_location (const struct event_location *src)
   return dst;
 }
 
+/* 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;
+
+  space = as_linespec ? ':' : ' ';
+  buf = mem_fileopen ();
+
+  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);
+  ui_file_delete (buf);
+  return result;
+}
+
+/* Return a malloc'd explicit string representation of the given
+   explicit location.  The location must already be canonicalized/valid.  */
+
+char *
+explicit_location_to_string (const struct explicit_location *explicit)
+{
+  return explicit_to_string_internal (0, explicit);
+}
+
+/* Return a malloc'd linespec string representation of the given
+   explicit location.  The location must already be canonicalized/valid.  */
+
+char *
+explicit_location_to_linespec (const struct explicit_location *explicit)
+{
+  return explicit_to_string_internal (1, explicit);
+}
+
 /* A cleanup function for struct event_location.  */
 
 static void
@@ -152,6 +305,12 @@ delete_event_location (struct event_location *location)
 	  /* Nothing to do.  */
 	  break;
 
+	case EXPLICIT_LOCATION:
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->source_filename);
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->function_name);
+	  xfree (EVENT_LOCATION_EXPLICIT (location)->label_name);
+	  break;
+
 	case PROBE_LOCATION:
 	  xfree (EVENT_LOCATION_PROBE (location));
 	  break;
@@ -189,6 +348,10 @@ event_location_to_string_const (const struct event_location *location)
 		      core_addr_to_string (EVENT_LOCATION_ADDRESS (location)));
       break;
 
+    case EXPLICIT_LOCATION:
+      result = explicit_location_to_string (EVENT_LOCATION_EXPLICIT (location));
+      break;
+
     case PROBE_LOCATION:
       result = xstrdup (EVENT_LOCATION_PROBE (location));
       break;
@@ -274,6 +437,14 @@ event_location_empty_p (const struct event_location *location)
     case ADDRESS_LOCATION:
       return 0;
 
+    case EXPLICIT_LOCATION:
+      return (EVENT_LOCATION_EXPLICIT (location) == NULL
+	      || (EVENT_LOCATION_EXPLICIT (location)->source_filename == NULL
+		  && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
+		  && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
+		  && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
+		      == LINE_OFFSET_UNKNOWN)));
+
     case PROBE_LOCATION:
       return EVENT_LOCATION_PROBE (location) == NULL;
 
diff --git a/gdb/location.h b/gdb/location.h
index e6f14d9..709d6f8 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -21,6 +21,32 @@
 
 struct language_defn;
 
+/* 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).  */
 
@@ -32,10 +58,35 @@ 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;
+};
+
 /* 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.  */
@@ -58,6 +109,10 @@ struct event_location
     /* An address in the inferior.  */
     CORE_ADDR address;
 #define EVENT_LOCATION_ADDRESS(S) ((S)->u.address)
+
+    /* An explicit location.  */
+    struct explicit_location explicit;
+#define EVENT_LOCATION_EXPLICIT(S) (&((S)->u.explicit))
   } u;
 
   /* Cached string representation of this location.  This is used to
@@ -65,6 +120,18 @@ struct event_location
   char *as_string;
 };
 
+/* 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, EVENT_LOCATION_LINESPEC and addr_string is NULL.
@@ -108,6 +175,15 @@ extern struct event_location *
 extern struct event_location *
   new_probe_location (const char *probe);
 
+/* 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 a copy of the given SRC location.  */
 
 extern struct event_location *
@@ -118,6 +194,10 @@ extern struct event_location *
 extern void initialize_event_location (struct event_location *location,
 				       enum event_location_type type);
 
+/* Initialize the given explicit location.  */
+
+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
    (malloc'd) if an event location was successfully found in *ARGP,

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

* Re: [RFA 6/9] Explicit locations v2 - Add explicit locations
  2014-05-30 18:19 ` Keith Seitz
@ 2014-08-03  1:50   ` Doug Evans
  2014-09-03 19:32     ` Keith Seitz
  0 siblings, 1 reply; 4+ messages in thread
From: Doug Evans @ 2014-08-03  1:50 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches@sourceware.org ml

Hi.
Several comments inline.

I still have patches 7,8,9 to go.
My plan is to get to them next week (fingers crossed, knock on wood,
and all that :-)).

Keith Seitz writes:
 > This is an update to this patch to incorporate changes from reviews of 
 > earlier patches.
 > 
 > Keith
 > 
 > Changes since last version:
 >    - remove SAVE_SPEC stuff
 >    - struct linespec: use struct explicit_location instead of
 >      all those strings/line_offset.
 >    - Add PARSER_EXPLICIT and use it where needed
 >    - No need to "convert linespec to explicit" -- the parser
 >      now builds an explicit location of the parsed result.
 >    - move string constructions out of canonicalize_linespec and into
 >      its own function
 >    - update comments on grammar of linespecs: expr_spec is now
 >      no longer considered a linespec.
 >    - add explicit_to_string_internal and use it to implement
 >      explicit_location_to_string/explicit_location_to_linespec
 >    - new_explicit_location
 >    - remove explicit_to_event_location
 > 
 > ChangeLog
 > 2014-05-29  Keith Seitz  <keiths@redhat.com>
 > 
 > 	* breakpoint.c (create_overlay_breakpoint): Convert linespec
 > 	into explicit location.
 > 	(create_longjmp_master_breakpoint): Likewise.
 > 	(create_std_terminate_master_breakpoint): Likewise.
 > 	(create_exception_master_breakpoint): Likewise.
 > 	(create_breakpoint): Update the SAVE_SPEC for explicit locations.
 > 	(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): Use PARSER_EXPLICIT to access the parser's
 > 	explicit location result.
 > 	(convert_linespec_to_sals): `ls' contains an explicit location.
 > 	Update all references.
 > 	(convert_explicit_location_to_sals): New function.
 > 	(linespec_parse_basic): 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 (initialize_explicit_location): New function.
 > 	(initialize_event_location): Initialize explicit locations.
 > 	(copy_event_location): Handle explicit locations.
 > 	(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.
 > 	(delete_event_location): Handle explicit locations.
 > 	(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.
 > 	(struct event_location.u) <explicit>: New member.
 > 	(EVENT_LOCATION_EXPLICIT): Define accessor macro.
 > 	(explicit_location_to_string): Declare.
 > 	(explicit_location_to_linespec): Declare.
 > 	(initialize_explicit_location): Declare.
 > 
 > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
 > index 345b104..d8c74c0 100644
 > --- a/gdb/breakpoint.c
 > +++ b/gdb/breakpoint.c
 > @@ -3281,6 +3281,7 @@ create_overlay_event_breakpoint (void)
 >        struct breakpoint *b;
 >        struct breakpoint_objfile_data *bp_objfile_data;
 >        CORE_ADDR addr;
 > +      struct explicit_location explicit;
 >  
 >        bp_objfile_data = get_breakpoint_objfile_data (objfile);
 >  
 > @@ -3305,7 +3306,9 @@ create_overlay_event_breakpoint (void)
 >        b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
 >                                        bp_overlay_event,
 >  				      &internal_breakpoint_ops);
 > -      b->location = new_linespec_location (func_name);
 > +      initialize_explicit_location (&explicit);
 > +      explicit.function_name = ASTRDUP (func_name);
 > +      b->location = new_explicit_location (&explicit);
 >  
 >        if (overlay_debugging == ovly_auto)
 >          {
 > @@ -3402,6 +3405,7 @@ create_longjmp_master_breakpoint (void)
 >  	  struct breakpoint *b;
 >  	  const char *func_name;
 >  	  CORE_ADDR addr;
 > +	  struct explicit_location explicit;
 >  
 >  	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
 >  	    continue;
 > @@ -3424,7 +3428,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);
 > -	  b->location = new_linespec_location (func_name);
 > +	  initialize_explicit_location (&explicit);
 > +	  explicit.function_name = ASTRDUP (func_name);
 > +	  b->location = new_explicit_location (&explicit);
 >  	  b->enable_state = bp_disabled;
 >  	}
 >      }
 > @@ -3455,6 +3461,7 @@ create_std_terminate_master_breakpoint (void)
 >      {
 >        struct breakpoint *b;
 >        struct breakpoint_objfile_data *bp_objfile_data;
 > +      struct explicit_location explicit;
 >  
 >        bp_objfile_data = get_breakpoint_objfile_data (objfile);
 >  
 > @@ -3480,7 +3487,9 @@ create_std_terminate_master_breakpoint (void)
 >        b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
 >                                        bp_std_terminate_master,
 >  				      &internal_breakpoint_ops);
 > -      b->location = new_linespec_location (func_name);
 > +      initialize_explicit_location (&explicit);
 > +      explicit.function_name = ASTRDUP (func_name);
 > +      b->location = new_explicit_location (&explicit);
 >        b->enable_state = bp_disabled;
 >      }
 >    }
 > @@ -3504,6 +3513,7 @@ create_exception_master_breakpoint (void)
 >        struct gdbarch *gdbarch;
 >        struct breakpoint_objfile_data *bp_objfile_data;
 >        CORE_ADDR addr;
 > +      struct explicit_location explicit;
 >  
 >        bp_objfile_data = get_breakpoint_objfile_data (objfile);
 >  
 > @@ -3584,7 +3594,9 @@ create_exception_master_breakpoint (void)
 >  						 &current_target);
 >        b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 >  				      &internal_breakpoint_ops);
 > -      b->location = new_linespec_location (func_name);
 > +      initialize_explicit_location (&explicit);
 > +      explicit.function_name = ASTRDUP (func_name);
 > +      b->location = new_explicit_location (&explicit);
 >        b->enable_state = bp_disabled;
 >      }
 >  
 > @@ -10010,6 +10022,20 @@ create_breakpoint (struct gdbarch *gdbarch,
 >        init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
 >        b->location = copy_event_location (location);
 >  
 > +      /* If the location has a string representation,
 > +	 save it to the breakpoint's location string cache, since this
 > +	 may be used to save the breakpoint to a file.  */
 > +      if (EVENT_LOCATION_TYPE (b->location) == EXPLICIT_LOCATION)
 > +	{
 > +	  char *old = event_location_to_string_const (location);
 > +
 > +	  b->location->as_string
 > +	    = xstrprintf ("%s%s%s", old,
 > +			  (extra_string == NULL ? "" : " "),
 > +			  (extra_string == NULL ? "" : extra_string));

Here's another case where a file outside of the event-location-specific code
is reaching into the internal implementation details of an event location.

Plus it's a bit confusing to do this:

      b->location = copy_event_location (location);

and then change the as_string representation of the location we just copied,
but only for EXPLICIT_LOCATION.  E.g., As the reader I'm left wondering
what happens to extra_string if the event location was a different kind.

Can you elaborate on what's going on here?

 > +	  xfree (old);
 > +	}
 > +
 >        if (parse_arg)
 >  	b->cond_string = NULL;
 >        else
 > @@ -10022,7 +10048,17 @@ create_breakpoint (struct gdbarch *gdbarch,
 >  	    }
 >  	  b->cond_string = cond_string;
 >  	}
 > -      b->extra_string = NULL;
 > +
 > +      /* For explicit locations, EXTRA_STRING may contain breakpoint
 > +	 condition information.  Make a private copy of this for the
 > +	 breakpoint.  */

The comment predicates itself on being specific to explicit locations,
but the code doesn't check for EXPLICIT_LOCATION.

Can you elaborate on what's going on here?

 > +      if (extra_string != NULL && *extra_string != '\0')
 > +	{
 > +	  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;
 > @@ -14212,6 +14248,7 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 >  	  struct symbol *sym;
 >  	  struct static_tracepoint_marker *tpmarker;
 >  	  struct ui_out *uiout = current_uiout;
 > +	  struct explicit_location explicit;
 >  
 >  	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
 >  
 > @@ -14253,11 +14290,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);
 > -	  b->location = new_linespec_location (NULL);
 > -	  EVENT_LOCATION_LINESPEC (b->location)
 > -	    = xstrprintf ("%s:%d",
 > -			  symtab_to_filename_for_display (sal2.symtab),
 > -			  b->loc->line_number);
 > +	  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);

Hmmm, the name new_explicit_location is ambiguous.
Does it return an explicit_location* or an event_location* ?
I like the consistency with new_linespec_location, new_address_location, etc.
so I understand why it's the latter, though my first guess would be the former
(though that would be confusing given that we're passing it an
explicit_location*).
No need to change anything, just thinking out loud.

 >  
 >  	  /* Might be nice to check if function changed, and warn if
 >  	     so.  */
 > diff --git a/gdb/linespec.c b/gdb/linespec.c
 > index deda86e..f141a86 100644
 > --- a/gdb/linespec.c
 > +++ b/gdb/linespec.c
 > @@ -66,73 +66,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;

Does this read better to you? [here, and at all uses]

  struct explicit_location location;

Dunno.
When I read "explicit" I'm left wondering "Does that mean there's an implicit
or some other possibility for the location that I have to think about?"
The struct definition is local to linespec.c so the scope of any confusion
is nicely confined, so I wouldn't make any change unless you think
it's worth it.

 >  
 >    /* 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.  */
 > @@ -141,10 +94,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;
 >  
 > @@ -197,6 +146,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
 > @@ -307,6 +259,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,
 > @@ -1550,6 +1506,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
 > @@ -1596,7 +1575,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.  */
 > @@ -1633,7 +1612,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);
 >      }
 > @@ -1647,7 +1626,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);
 >  	}
 > @@ -1655,14 +1634,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;
 >  	    }
 > @@ -1677,7 +1656,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;
 >  	}
 > @@ -1697,7 +1676,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);
 >  
 > @@ -1717,16 +1696,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.  */
 > @@ -1744,7 +1722,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);
 >  
 > @@ -1761,42 +1739,19 @@ 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, linespec_p ls)
 >  {
 > -  struct ui_file *buf;
 > -  int need_colon = 0;
 > -
 >    /* If canonicalization was not requested, no need to do anything.  */
 >    if (!state->canonical)

No requested change here.
I just wanted to note that here's a good example where
"if (state->canonical == NULL)" would be clearer.
At this point in my reading for half a second I wondered if canonical was
a boolean, and was confused because the function comment said the result
was stored there.

 >      return;
 >  
 > -  buf = mem_fileopen ();
 > -
 > -  state->canonical->location = new_linespec_location (NULL);
 > -
 > -  if (ls->source_filename)
 > +  if (ls->explicit.label_name)
 >      {
 > -      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;
 > -    }
 > -
 > -  if (ls->label_name)
 > -    {
 > -      if (need_colon)
 > -	fputc_unfiltered (':', buf);
 > -
 > -      if (ls->function_name == NULL)
 > +      if (ls->explicit.function_name == NULL)
 >  	{
 >  	  struct symbol *s;
 >  
 > @@ -1805,29 +1760,22 @@ canonicalize_linespec (struct linespec_state *state, 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);
 > +	  ls->explicit.function_name = xstrdup (SYMBOL_NATURAL_NAME (s));

This is a side-effect not adequately explained in the function comment.
It's not clear from the function comment that LS is modified.
Is the side-effect necessary (in which case let's make the function
comment clearer), or can we avoid it?

 >  	}
 >  
 > -      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);
 > -    }
 > +  /* Save everything as an explicit location.  */
 > +  state->canonical->location = new_explicit_location (&ls->explicit);
 >  
 > -  EVENT_LOCATION_LINESPEC (state->canonical->location)
 > -    = ui_file_xstrdup (buf, NULL);
 > -  ui_file_delete (buf);
 > +  /* Save a string representation of this linespec.  */
 > +  if (state->is_linespec)
 > +    state->canonical->location->as_string
 > +      = explicit_location_to_linespec (&ls->explicit);
 > +  else
 > +    state->canonical->location->as_string
 > +      = explicit_location_to_string (&ls->explicit);

Why do we need to set as_string here again?
Can users of it call event_location_to_string themselves?
There's still the state->is_linespec distinction of course,
feels odd to have it though: something outside of an event_location
is deciding what to store there, feels like an abstraction violation.

 >  }
 >  
 >  /* Given a line offset in LS, construct the relevant SALs.  */
 > @@ -1867,18 +1815,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;
 > @@ -1970,9 +1918,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);
 > @@ -2072,13 +2020,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);
 >  
 > @@ -2086,7 +2034,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
 > @@ -2103,6 +2051,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,
 > +				   struct explicit_location *explicit)

How many of these parameters can be const?

 > +{
 > +  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.
 >     Pass the address of a char * variable; that variable will be
 >     advanced over the characters actually parsed.
 > @@ -2215,13 +2230,13 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 >        /* 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);
 > @@ -2257,7 +2272,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 >        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);
 > @@ -2294,7 +2309,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 >  
 >    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
 > @@ -2303,8 +2318,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 >  	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:
 > @@ -2342,6 +2357,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.  */
 > @@ -2356,7 +2372,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);
 >  }
 > @@ -2376,10 +2392,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);
 > @@ -2415,6 +2430,7 @@ event_location_to_sals (linespec_parser *parser,
 >  	const char *copy, *orig;
 >  	volatile struct gdb_exception except;
 >  
 > +	PARSER_STATE (parser)->is_linespec = 1;
 >  	TRY_CATCH (except, RETURN_MASK_ERROR)
 >  	  {
 >  	    orig = copy = EVENT_LOCATION_LINESPEC (location);
 > @@ -2433,6 +2449,17 @@ event_location_to_sals (linespec_parser *parser,
 >  					    EVENT_LOCATION_ADDRESS (location));
 >        break;
 >  
 > +    case EXPLICIT_LOCATION:
 > +      {
 > +	struct explicit_location *explicit;
 > +
 > +	explicit = EVENT_LOCATION_EXPLICIT (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");
 > @@ -2691,7 +2718,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
 >        memcpy (saved_arg, *argptr, new_argptr - *argptr);
 >        saved_arg[new_argptr - *argptr] = '\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);
 > @@ -2701,9 +2728,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
 >  	  self->canonical->pre_expanded = 1;
 >  	  self->canonical->location = new_linespec_location (NULL);
 >  
 > -	  if (ls->source_filename)
 > +	  if (ls->explicit.source_filename)
 >  	    EVENT_LOCATION_LINESPEC (self->canonical->location)
 > -	      = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
 > +	      = xstrprintf ("%s:%s", ls->explicit.source_filename, saved_arg);
 >  	  else
 >  	    EVENT_LOCATION_LINESPEC (self->canonical->location)
 >  	      = xstrdup (saved_arg);
 > @@ -3082,7 +3109,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 eafa27d..86d4232 100644
 > --- a/gdb/location.c
 > +++ b/gdb/location.c
 > @@ -28,6 +28,15 @@
 >  #include <ctype.h>
 >  #include <string.h>
 >  
 > +/* Initialize the given explicit location.  */
 > +
 > +void
 > +initialize_explicit_location (struct explicit_location *explicit)
 > +{
 > +  memset (explicit, 0, sizeof (struct explicit_location));
 > +  explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
 > +}
 > +
 >  /* Initialize the given LOCATION.  */
 >  
 >  void
 > @@ -36,6 +45,8 @@ initialize_event_location (struct event_location *location,
 >  {
 >    memset (location, 0, sizeof (struct event_location));
 >    EVENT_LOCATION_TYPE (location) = type;
 > +  if (type == EXPLICIT_LOCATION)
 > +    initialize_explicit_location (EVENT_LOCATION_EXPLICIT (location));
 >  }
 >  
 >  /* Create a new linespec location.  The return result is malloc'd
 > @@ -82,6 +93,49 @@ new_probe_location (const char *probe)
 >    return 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.  */
 > +
 > +struct event_location *
 > +new_explicit_location (const struct explicit_location *explicit)
 > +{
 > +  struct event_location tmp;
 > +
 > +  initialize_event_location (&tmp, EXPLICIT_LOCATION);
 > +
 > +  if (explicit != NULL)
 > +    {
 > +      if (explicit->source_filename != NULL)
 > +	{
 > +	  /* Error check -- we must have one of the other
 > +	     parameters specified.  */
 > +	  if (explicit->function_name == NULL
 > +	      && explicit->label_name == NULL
 > +	      && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
 > +	    error (_("Source filename requires function, label, or "
 > +		     "line offset."));

How about moving this error check into the caller(s)
and have an assert here instead?  One could write a utility to
error check an explicit_location, and the callers could call that.

 > +
 > +	  EVENT_LOCATION_EXPLICIT (&tmp)->source_filename
 > +	    = explicit->source_filename;
 > +	}
 > +
 > +      if (explicit->function_name != NULL)
 > +	EVENT_LOCATION_EXPLICIT (&tmp)->function_name
 > +	  = explicit->function_name;
 > +
 > +      if (explicit->label_name != NULL)
 > +	EVENT_LOCATION_EXPLICIT (&tmp)->label_name = explicit->label_name;
 > +
 > +      if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
 > +	EVENT_LOCATION_EXPLICIT (&tmp)->line_offset = explicit->line_offset;
 > +    }
 > +
 > +  return copy_event_location (&tmp);
 > +}
 > +
 >  /* Return a copy of the given SRC location.  */
 >  
 >  struct event_location *
 > @@ -104,6 +158,24 @@ copy_event_location (const struct event_location *src)
 >        EVENT_LOCATION_ADDRESS (dst) = EVENT_LOCATION_ADDRESS (src);
 >        break;
 >  
 > +    case EXPLICIT_LOCATION:
 > +      if (EVENT_LOCATION_EXPLICIT (src)->source_filename != NULL)
 > +	EVENT_LOCATION_EXPLICIT (dst)->source_filename
 > +	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->source_filename);
 > +
 > +      if (EVENT_LOCATION_EXPLICIT (src)->function_name != NULL)
 > +	EVENT_LOCATION_EXPLICIT (dst)->function_name
 > +	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->function_name);
 > +
 > +      if (EVENT_LOCATION_EXPLICIT (src)->label_name != NULL)
 > +	EVENT_LOCATION_EXPLICIT (dst)->label_name
 > +	  = xstrdup (EVENT_LOCATION_EXPLICIT (src)->label_name);
 > +
 > +      EVENT_LOCATION_EXPLICIT (dst)->line_offset
 > +	= EVENT_LOCATION_EXPLICIT (src)->line_offset;
 > +      break;
 > +
 > +
 >      case PROBE_LOCATION:
 >        EVENT_LOCATION_PROBE (dst) = xstrdup (EVENT_LOCATION_PROBE (src));
 >        break;
 > @@ -115,6 +187,87 @@ copy_event_location (const struct event_location *src)
 >    return dst;
 >  }
 >  
 > +/* 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;
 > +
 > +  space = as_linespec ? ':' : ' ';
 > +  buf = mem_fileopen ();
 > +
 > +  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);
 > +  ui_file_delete (buf);
 > +  return result;
 > +}
 > +
 > +/* Return a malloc'd explicit string representation of the given
 > +   explicit location.  The location must already be canonicalized/valid.  */
 > +
 > +char *
 > +explicit_location_to_string (const struct explicit_location *explicit)
 > +{
 > +  return explicit_to_string_internal (0, explicit);
 > +}
 > +
 > +/* Return a malloc'd linespec string representation of the given
 > +   explicit location.  The location must already be canonicalized/valid.  */
 > +
 > +char *
 > +explicit_location_to_linespec (const struct explicit_location *explicit)
 > +{
 > +  return explicit_to_string_internal (1, explicit);
 > +}
 > +
 >  /* A cleanup function for struct event_location.  */
 >  
 >  static void
 > @@ -152,6 +305,12 @@ delete_event_location (struct event_location *location)
 >  	  /* Nothing to do.  */
 >  	  break;
 >  
 > +	case EXPLICIT_LOCATION:
 > +	  xfree (EVENT_LOCATION_EXPLICIT (location)->source_filename);
 > +	  xfree (EVENT_LOCATION_EXPLICIT (location)->function_name);
 > +	  xfree (EVENT_LOCATION_EXPLICIT (location)->label_name);
 > +	  break;
 > +
 >  	case PROBE_LOCATION:
 >  	  xfree (EVENT_LOCATION_PROBE (location));
 >  	  break;
 > @@ -189,6 +348,10 @@ event_location_to_string_const (const struct event_location *location)
 >  		      core_addr_to_string (EVENT_LOCATION_ADDRESS (location)));
 >        break;
 >  
 > +    case EXPLICIT_LOCATION:
 > +      result = explicit_location_to_string (EVENT_LOCATION_EXPLICIT (location));
 > +      break;
 > +
 >      case PROBE_LOCATION:
 >        result = xstrdup (EVENT_LOCATION_PROBE (location));
 >        break;
 > @@ -274,6 +437,14 @@ event_location_empty_p (const struct event_location *location)
 >      case ADDRESS_LOCATION:
 >        return 0;
 >  
 > +    case EXPLICIT_LOCATION:
 > +      return (EVENT_LOCATION_EXPLICIT (location) == NULL
 > +	      || (EVENT_LOCATION_EXPLICIT (location)->source_filename == NULL
 > +		  && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
 > +		  && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
 > +		  && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
 > +		      == LINE_OFFSET_UNKNOWN)));
 > +
 >      case PROBE_LOCATION:
 >        return EVENT_LOCATION_PROBE (location) == NULL;
 >  
 > diff --git a/gdb/location.h b/gdb/location.h
 > index e6f14d9..709d6f8 100644
 > --- a/gdb/location.h
 > +++ b/gdb/location.h
 > @@ -21,6 +21,32 @@
 >  
 >  struct language_defn;
 >  
 > +/* 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).  */
 >  
 > @@ -32,10 +58,35 @@ 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;
 > +};
 > +
 >  /* 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.  */
 > @@ -58,6 +109,10 @@ struct event_location
 >      /* An address in the inferior.  */
 >      CORE_ADDR address;
 >  #define EVENT_LOCATION_ADDRESS(S) ((S)->u.address)
 > +
 > +    /* An explicit location.  */
 > +    struct explicit_location explicit;
 > +#define EVENT_LOCATION_EXPLICIT(S) (&((S)->u.explicit))
 >    } u;
 >  
 >    /* Cached string representation of this location.  This is used to
 > @@ -65,6 +120,18 @@ struct event_location
 >    char *as_string;
 >  };
 >  
 > +/* 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, EVENT_LOCATION_LINESPEC and addr_string is NULL.
 > @@ -108,6 +175,15 @@ extern struct event_location *
 >  extern struct event_location *
 >    new_probe_location (const char *probe);
 >  
 > +/* 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.  */

Copy of function comment in .c file.  Delete one.

 > +
 > +extern struct event_location *
 > +  new_explicit_location (const struct explicit_location *explicit);
 > +
 >  /* Return a copy of the given SRC location.  */
 >  
 >  extern struct event_location *
 > @@ -118,6 +194,10 @@ extern struct event_location *
 >  extern void initialize_event_location (struct event_location *location,
 >  				       enum event_location_type type);
 >  
 > +/* Initialize the given explicit location.  */
 > +
 > +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
 >     (malloc'd) if an event location was successfully found in *ARGP,

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

* Re: [RFA 6/9] Explicit locations v2 - Add explicit locations
  2014-08-03  1:50   ` Doug Evans
@ 2014-09-03 19:32     ` Keith Seitz
  0 siblings, 0 replies; 4+ messages in thread
From: Keith Seitz @ 2014-09-03 19:32 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches@sourceware.org ml

[-- Attachment #1: Type: text/plain, Size: 12184 bytes --]

On 08/02/2014 06:49 PM, Doug Evans wrote:
> Keith Seitz writes:
>
>   > @@ -10010,6 +10022,20 @@ create_breakpoint (struct gdbarch *gdbarch,
>   >        init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
>   >        b->location = copy_event_location (location);
>   >
>   > +      /* If the location has a string representation,
>   > +	 save it to the breakpoint's location string cache, since this
>   > +	 may be used to save the breakpoint to a file.  */
>   > +      if (EVENT_LOCATION_TYPE (b->location) == EXPLICIT_LOCATION)
>   > +	{
>   > +	  char *old = event_location_to_string_const (location);
>   > +
>   > +	  b->location->as_string
>   > +	    = xstrprintf ("%s%s%s", old,
>   > +			  (extra_string == NULL ? "" : " "),
>   > +			  (extra_string == NULL ? "" : extra_string));
>
> Here's another case where a file outside of the event-location-specific code
> is reaching into the internal implementation details of an event location.
>

I've added a function for this.

> Plus it's a bit confusing to do this:
>
>        b->location = copy_event_location (location);
>
> and then change the as_string representation of the location we just copied,
> but only for EXPLICIT_LOCATION.  E.g., As the reader I'm left wondering
> what happens to extra_string if the event location was a different kind.
>
> Can you elaborate on what's going on here?

I've changed this a bit... If extra_string is not NULL, the code now 
ALWAYS appends this to the string representation it saves. This block of 
code was moved earlier where the pending breakpoint was first detected 
(in the big switch block after TRY_CATCH).

However, this string representation must still be saved to the (pending) 
breakpoint's location. Since we don't have a resolved 
breakpoint/location, we need a way to serialize the given location. That 
was computed earlier (again the big switch statement). So now, the code 
uses that.

>   > +
>   > +      /* For explicit locations, EXTRA_STRING may contain breakpoint
>   > +	 condition information.  Make a private copy of this for the
>   > +	 breakpoint.  */
>
> The comment predicates itself on being specific to explicit locations,
> but the code doesn't check for EXPLICIT_LOCATION.
>
> Can you elaborate on what's going on here?

This was removed. [Or more properly, it was moved, as I discuss right 
above.]

>   > @@ -14253,11 +14290,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);
>   > -	  b->location = new_linespec_location (NULL);
>   > -	  EVENT_LOCATION_LINESPEC (b->location)
>   > -	    = xstrprintf ("%s:%d",
>   > -			  symtab_to_filename_for_display (sal2.symtab),
>   > -			  b->loc->line_number);
>   > +	  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);
>
> Hmmm, the name new_explicit_location is ambiguous.
> Does it return an explicit_location* or an event_location* ?
> I like the consistency with new_linespec_location, new_address_location, etc.
> so I understand why it's the latter, though my first guess would be the former
> (though that would be confusing given that we're passing it an
> explicit_location*).
> No need to change anything, just thinking out loud.

Yeah, there's a lot of unfortunate naming fallout. As you correctly 
deduce, I kept the ctors names consistent. Likewise with the 
get_*_locations:

function                 takes                returns
--------                 -----                -------
new_linespec_location    char*                event_location*
get_linespec_location    event_location*      char*
new_address_location     CORE_ADDR            event_location*
get_address_location     event_location*      CORE_ADDR
new_probe_location       char*                event_location*
get_probe_location       event_location*      char*
new_explicit_location    explicit_location*   event_location*
get_explicit_location    event_location*      explicit_location*

>   > -  /* 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;
>
> Does this read better to you? [here, and at all uses]
>
>    struct explicit_location location;
>
> Dunno.

My convention has been to reserve the generic "location" as meaning an 
(struct) event_location.

> When I read "explicit" I'm left wondering "Does that mean there's an implicit
> or some other possibility for the location that I have to think about?"

In this context, of course, the answer is "no." :-) An explicit location 
is an explicit location. It can be nothing else. If it said (instead) 
"struct event_location explicit;" I would agree -- that *does/would* 
leave me wondering about other possibilities. But then I've been staring 
at this for so long, I probably take (too much) for granted!

> The struct definition is local to linespec.c so the scope of any confusion
> is nicely confined, so I wouldn't make any change unless you think
> it's worth it.

I could change it to "explicit_location"?

>   > @@ -1761,42 +1739,19 @@ 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, linespec_p ls)
>   >  {
>   > -  struct ui_file *buf;
>   > -  int need_colon = 0;
>   > -
>   >    /* If canonicalization was not requested, no need to do anything.  */
>   >    if (!state->canonical)
>
> No requested change here.
> I just wanted to note that here's a good example where
> "if (state->canonical == NULL)" would be clearer.
> At this point in my reading for half a second I wondered if canonical was
> a boolean, and was confused because the function comment said the result
> was stored there.

FYI, I didn't change that line. I've been called-out many times on 
making unrelated/superfluous changes, so I've left it (and other similar 
places) alone.

>   > @@ -1805,29 +1760,22 @@ canonicalize_linespec (struct linespec_state *state, 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);
>   > +	  ls->explicit.function_name = xstrdup (SYMBOL_NATURAL_NAME (s));
>
> This is a side-effect not adequately explained in the function comment.
> It's not clear from the function comment that LS is modified.
> Is the side-effect necessary (in which case let's make the function
> comment clearer), or can we avoid it?

I agree. I don't know why I did that. To be more strict, I've changed 
this function to take a const linespec_p. Obviously, what I meant to do 
(or should have done) is canonicalize the canonical location in STATE.

>   > -  EVENT_LOCATION_LINESPEC (state->canonical->location)
>   > -    = ui_file_xstrdup (buf, NULL);
>   > -  ui_file_delete (buf);
>   > +  /* Save a string representation of this linespec.  */
>   > +  if (state->is_linespec)
>   > +    state->canonical->location->as_string
>   > +      = explicit_location_to_linespec (&ls->explicit);
>   > +  else
>   > +    state->canonical->location->as_string
>   > +      = explicit_location_to_string (&ls->explicit);
>
> Why do we need to set as_string here again?
> Can users of it call event_location_to_string themselves?
> There's still the state->is_linespec distinction of course,
> feels odd to have it though: something outside of an event_location
> is deciding what to store there, feels like an abstraction violation.

Yes, this is one of the scenarios I discussed in a previous revision 
(#2/9). Since all linespecs are converted to explicit form /and/ we 
compute string serializations of event_locations on demand, we need a 
way to discern between explicit and linespec locations.

There are two ways to do this:
1) Add a flag to event_location to indicate that this location really 
represents a linespec (and use that flag later when computing the string)
2) Save the linespec representation when the linespec is converted to 
explicit.

Not seeing any immediate advantage, I've chosen #2.

>   > +/* Convert the explicit location EXPLICIT into SaLs.  */
>   > +
>   > +static struct symtabs_and_lines
>   > +convert_explicit_location_to_sals (struct linespec_state *self,
>   > +				   linespec_p result,
>   > +				   struct explicit_location *explicit)
>
> How many of these parameters can be const?

Only the last. [I've changed that in this revision.] Obviously we need 
to be able to manipulate RESULT, but other functions need to use SELF, 
too, for storing symbol search iterator information.

>   > @@ -82,6 +93,49 @@ new_probe_location (const char *probe)
>   >    return 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.  */
>   > +
>   > +struct event_location *
>   > +new_explicit_location (const struct explicit_location *explicit)
>   > +{
>   > +  struct event_location tmp;
>   > +
>   > +  initialize_event_location (&tmp, EXPLICIT_LOCATION);
>   > +
>   > +  if (explicit != NULL)
>   > +    {
>   > +      if (explicit->source_filename != NULL)
>   > +	{
>   > +	  /* Error check -- we must have one of the other
>   > +	     parameters specified.  */
>   > +	  if (explicit->function_name == NULL
>   > +	      && explicit->label_name == NULL
>   > +	      && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
>   > +	    error (_("Source filename requires function, label, or "
>   > +		     "line offset."));
>
> How about moving this error check into the caller(s)
> and have an assert here instead?  One could write a utility to
> error check an explicit_location, and the callers could call that.

Ha. Great idea. I can only guess this was necessary at some time. I've 
double-checked it all, and it is /not/ necessary for the CLI. I have 
added something to MI to check this.

>   > @@ -108,6 +175,15 @@ extern struct event_location *
>   >  extern struct event_location *
>   >    new_probe_location (const char *probe);
>   >
>   > +/* 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.  */
>
> Copy of function comment in .c file.  Delete one.

I've removed all the duplicate function comments from location.c and 
replaced them with "See description in location.h."

Updated patch attached.

Keith

Changes since last revision:
   - Save extra_string for all locations (pending bps)
   - canonicalize_linespec: have explicit label but no function,
     set function; We need it for:
    (gdb) start
    (gdb) b -label done
    (gdb) save breakpoints bps
    (gdb) shell cat bps
    break -label done <-- not correct!
    We need "--function main" added, just like in the linespec case.
    I've made it so that the behavior is EXACTLY the same
    as linespec case, made LS const, and saved everything in the
    canonical location.
    - make EXPLICIT const in convert_explicit_location_to_sals
    - canonicalize_linespec: only save string representation for
      linespec.  Needed so that we display linespecs as linespecs.
      Other option is to not do this and save is_linespec somewhere
    - new_explicit_location: remove error check
    - removed duplicate function comments


[-- Attachment #2: explicit-explicit-locations.patch --]
[-- Type: text/x-patch, Size: 39382 bytes --]

gdb/ChangeLog:

	* breakpoint.c (create_overlay_breakpoint): Convert linespec
	into explicit location.
	(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): Use PARSER_EXPLICIT to access the parser's
	explicit location result.
	(convert_linespec_to_sals): `ls' contains an explicit location.
	Update all references.
	(convert_explicit_location_to_sals): New function.
	(linespec_parse_basic): 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.
	(copy_event_location): Handle explicit locations.
	(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.
	(delete_event_location): Handle explicit locations.
	(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.
	(initialize_explicit_location): Declare.
---
 gdb/breakpoint.c |   48 +++++++--
 gdb/linespec.c   |  303 ++++++++++++++++++++++++++++++------------------------
 gdb/location.c   |  167 ++++++++++++++++++++++++++++++
 gdb/location.h   |   82 +++++++++++++++
 4 files changed, 453 insertions(+), 147 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0fceeac..c25b02f 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3281,6 +3281,7 @@ create_overlay_event_breakpoint (void)
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3305,7 +3306,9 @@ create_overlay_event_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_overlay_event,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
 
       if (overlay_debugging == ovly_auto)
         {
@@ -3402,6 +3405,7 @@ create_longjmp_master_breakpoint (void)
 	  struct breakpoint *b;
 	  const char *func_name;
 	  CORE_ADDR addr;
+	  struct explicit_location explicit;
 
 	  if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
 	    continue;
@@ -3424,7 +3428,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);
-	  b->location = new_linespec_location (func_name);
+	  initialize_explicit_location (&explicit);
+	  explicit.function_name = ASTRDUP (func_name);
+	  b->location = new_explicit_location (&explicit);
 	  b->enable_state = bp_disabled;
 	}
     }
@@ -3455,6 +3461,7 @@ create_std_terminate_master_breakpoint (void)
     {
       struct breakpoint *b;
       struct breakpoint_objfile_data *bp_objfile_data;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3480,7 +3487,9 @@ create_std_terminate_master_breakpoint (void)
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
                                       bp_std_terminate_master,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
   }
@@ -3504,6 +3513,7 @@ create_exception_master_breakpoint (void)
       struct gdbarch *gdbarch;
       struct breakpoint_objfile_data *bp_objfile_data;
       CORE_ADDR addr;
+      struct explicit_location explicit;
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
@@ -3584,7 +3594,9 @@ create_exception_master_breakpoint (void)
 						 &current_target);
       b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
 				      &internal_breakpoint_ops);
-      b->location = new_linespec_location (func_name);
+      initialize_explicit_location (&explicit);
+      explicit.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit);
       b->enable_state = bp_disabled;
     }
 
@@ -9890,8 +9902,21 @@ create_breakpoint (struct gdbarch *gdbarch,
 	     is defaulted on behalf of the user.  */
 	  {
 	    struct linespec_sals lsal;
+	    char *estr = event_location_to_string_const (location);
 
-	    lsal.canonical = event_location_to_string_const (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;
+
+		new = xstrprintf ("%s %s", estr, extra_string);
+		xfree (estr);
+		estr = new;
+	      }
+
+	    lsal.canonical = estr;
 	    lsal.sals.nelts = 1;
 	    lsal.sals.sals = XNEW (struct symtab_and_line);
 	    init_sal (&lsal.sals.sals[0]);
@@ -14223,11 +14248,11 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 
       if (!VEC_empty(static_tracepoint_marker_p, markers))
 	{
-	  char *tmp;
 	  struct symtab_and_line sal2;
 	  struct symbol *sym;
 	  struct static_tracepoint_marker *tpmarker;
 	  struct ui_out *uiout = current_uiout;
+	  struct explicit_location explicit;
 
 	  tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
 
@@ -14269,11 +14294,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);
-	  tmp = xstrprintf ("%s:%d",
-			    symtab_to_filename_for_display (sal2.symtab),
-			    b->loc->line_number);
-	  b->location = new_linespec_location (tmp);
-	  xfree (tmp);
+	  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 bc4484f..a529457 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -66,73 +66,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.  */
@@ -141,10 +94,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;
 
@@ -197,6 +146,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
@@ -307,6 +259,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,
@@ -1550,6 +1506,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
@@ -1596,7 +1575,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.  */
@@ -1633,7 +1612,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);
     }
@@ -1647,7 +1626,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);
 	}
@@ -1655,14 +1634,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;
 	    }
@@ -1677,7 +1656,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;
 	}
@@ -1697,7 +1676,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);
 
@@ -1717,16 +1696,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.  */
@@ -1744,7 +1722,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);
 
@@ -1761,41 +1739,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, linespec_p ls)
+canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 {
-  char *tmp;
-  struct ui_file *buf;
-  int need_colon = 0;
+  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 ();
-
-  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;
 
@@ -1804,30 +1769,17 @@ canonicalize_linespec (struct linespec_state *state, 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);
-  state->canonical->location = new_linespec_location (tmp);
-  xfree (tmp);
-  ui_file_delete (buf);
 }
 
 /* Given a line offset in LS, construct the relevant SALs.  */
@@ -1867,18 +1819,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;
@@ -1970,9 +1922,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);
@@ -2072,13 +2024,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);
 
@@ -2086,7 +2038,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
@@ -2103,6 +2055,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.
    Pass the address of a char * variable; that variable will be
    advanced over the characters actually parsed.
@@ -2215,13 +2234,13 @@ parse_linespec (linespec_parser *parser, const char **argptr)
       /* 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);
@@ -2257,7 +2276,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
       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);
@@ -2294,7 +2313,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 
   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
@@ -2303,8 +2322,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
 	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:
@@ -2342,6 +2361,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.  */
@@ -2356,7 +2376,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);
 }
@@ -2376,10 +2396,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);
@@ -2415,6 +2434,7 @@ event_location_to_sals (linespec_parser *parser,
 	const char *copy, *orig;
 	volatile struct gdb_exception except;
 
+	PARSER_STATE (parser)->is_linespec = 1;
 	TRY_CATCH (except, RETURN_MASK_ERROR)
 	  {
 	    orig = copy = get_linespec_location (location);
@@ -2433,6 +2453,17 @@ event_location_to_sals (linespec_parser *parser,
 					    get_address_location (location));
       break;
 
+    case EXPLICIT_LOCATION:
+      {
+	struct explicit_location *explicit;
+
+	explicit = get_explicit_location (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");
@@ -2691,7 +2722,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
       memcpy (saved_arg, *argptr, new_argptr - *argptr);
       saved_arg[new_argptr - *argptr] = '\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);
@@ -2702,10 +2733,10 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
 
 	  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);
@@ -3087,7 +3118,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 8d8fa89..9faad40 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 (const char *linespec)
 {
@@ -137,6 +150,126 @@ get_probe_location (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);
+}
+
+/* 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;
+
+  space = as_linespec ? ':' : ' ';
+  buf = mem_fileopen ();
+
+  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);
+  ui_file_delete (buf);
+  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;
@@ -157,6 +290,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));
@@ -206,6 +355,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;
@@ -252,6 +407,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;
@@ -331,6 +490,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 fa4d0f5..0adb0c5 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,21 @@ extern struct event_location *
 extern char *
   get_probe_location (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);
+
 /* Free an event location and any associated data.  */
 
 extern void delete_event_location (struct event_location *location);
@@ -115,6 +193,10 @@ extern struct event_location *
 extern struct event_location *
   copy_event_location_tmp (const struct event_location *src);
 
+/* Initialize the given explicit location.  */
+
+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
    (malloc'd) if an event location was successfully found in *ARGP,

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

end of thread, other threads:[~2014-09-03 19:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-08 18:02 [RFA 6/9] Explicit locations v2 - Add explicit locations Keith Seitz
2014-05-30 18:19 ` Keith Seitz
2014-08-03  1:50   ` Doug Evans
2014-09-03 19:32     ` Keith Seitz

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