[RFA,6/9] Explicit locations v2 - Add explicit locations

Message ID 536BC6C6.6040501@redhat.com
State Superseded
Headers

Commit Message

Keith Seitz May 8, 2014, 6:02 p.m. UTC
  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.
  

Patch

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,