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


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

[RFA 3/5] Explicit linespecs - implementation


Hi,

Ok, so here's what everyone has been waiting for. This patch adds the implementation of explicit linespecs, including CLI and MI support.

Reminder: You must apply the previous patch (breakpoint-api) before applying this patch.

Questions/comments/concerns?
Keith

ChangeLog
2012-07-26  Keith Seitz  <keiths@redhat.com>

	* breakpoint.h (struct breakpoint): Add EXPLICIT.
	* breakpoint.c (update_breakpoints_after_exec):
	Don't delete the breakpoint if B->EXPLICIT is non-NULL.
	(print_breakpoint_location): For pending explicit breakpoints,
	use explicit_linespec_to_string to print out an appropriate
	address string.
	(explicit_linespec_unsupported): New function.
	(init_breakpoint_sal): If ELS in non-NULL, copy it into
	the struct breakpoint.
	(parse_breakpoint_sals): If ELS is non-NULL, call
	decode_explicit_linespec instead of decode_line_full.
	(create_breakpoint_1): Deal with explicit linespecs.
	(break_command_1): Check for an explicit linespec.
	(say_where): For pending explicit breakpoints, use
	explicit_linepsec_to_string to print out an address string.
	(base_breakpoint_dtor): Free any explicit_linespec associated
	with the breakpoint.
	(bkpt_re_set): Don't delete the breakpoint if B->EXPLICIT
	is non-NULL.
	(strace_marker_decode_linespec): Error if explicit_linespec
	is non-NULL.
	(decode_linespec_default): Call decode_explicit_linespec if
	explicit_linespec is non-NULL.
	* linespec.h (struct linespec_result): Add EXPLICIT.
	(new_explicit_linespec, free_explicit_linespec,
	copy_explicit_linespec, explicit_linespec_to_string,
	string_to_explicit_linespec,
	decode_explicit_linespec): Declare.
	* linespec.c (canonicalize_linespec): Build an explicit linespec
	representation, too.
	(destroy_linespec_result): Free the explicit_linespec.
	(new_explicit_linespec, free_explicit_linespec,
	explicit_lex_one, string_to_explicit_linespec,
	copy_explicit_linespec, explicit_linespec_to_string):
	New functions.
	* mi/mi-cmd-break.c: Include linespec.h.
	(mi_cmd_break_insert): Add options for explicit
	linespecs and pass them to create_breakpoint.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 35d55ba..1058a35 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3486,7 +3486,7 @@ update_breakpoints_after_exec (void)
     /* Without a symbolic address, we have little hope of the
        pre-exec() address meaning the same thing in the post-exec()
        a.out.  */
-    if (b->addr_string == NULL)
+    if (b->addr_string == NULL && b->explicit == NULL)
       {
 	delete_breakpoint (b);
 	continue;
@@ -5688,7 +5688,19 @@ print_breakpoint_location (struct breakpoint *b,
       do_cleanups (stb_chain);
     }
   else
-    ui_out_field_string (uiout, "pending", b->addr_string);
+    {
+      char *where = b->addr_string;
+      struct cleanup *free_where = make_cleanup (null_cleanup, NULL);
+
+      if (b->explicit != NULL)
+	{
+	  where = explicit_linespec_to_string (b->explicit, b->addr_string);
+	  make_cleanup (xfree, where);
+	}
+
+      ui_out_field_string (uiout, "pending", where);
+      do_cleanups (free_where);
+    }
 
   if (loc && is_breakpoint (b)
       && breakpoint_condition_evaluation_mode () == condition_evaluation_target
@@ -5757,6 +5769,14 @@ bptype_string (enum bptype type)
   return bptypes[(int) type].description;
 }
 
+/* Throw an exception for unsupported explicit linespec.  */
+
+static void ATTRIBUTE_NORETURN
+explicit_linespec_unsupported (enum bptype type)
+{
+  error (_("explicit linespec not supported for %s"), bptype_string (type));
+}
+
 /* Print B to gdb_stdout.  */
 
 static void
@@ -9009,6 +9029,8 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
        me.  */
     b->addr_string
       = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+  if (els != NULL)
+    b->explicit = copy_explicit_linespec (els);
   b->filter = filter;
 }
 
@@ -9040,7 +9062,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
   old_chain = make_cleanup (xfree, b);
 
   init_breakpoint_sal (b, gdbarch,
-		       sals, NULL, addr_string,
+		       sals, els, addr_string,
 		       filter, cond_string, extra_string,
 		       type, disposition,
 		       thread, task, ignore_count,
@@ -9094,7 +9116,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 
       make_cleanup (xfree, filter_string);
       create_breakpoint_sal (gdbarch, lsal->sals,
-			     NULL, addr_string,
+			     canonical->explicit, addr_string,
 			     filter_string,
 			     cond_string, extra_string,
 			     type, disposition,
@@ -9121,8 +9143,9 @@ parse_breakpoint_sals (explicit_linespec *els, char **address,
 
   /* If no arg given, or if first arg is 'if ', use the default
      breakpoint.  */
-  if ((*address) == NULL
-      || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
+  if (els == NULL
+      && ((*address) == NULL
+	  || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2]))))
     {
       /* The last displayed codepoint, if it's valid, is our default breakpoint
          address.  */
@@ -9167,17 +9190,33 @@ parse_breakpoint_sals (explicit_linespec *els, char **address,
 
 	 ObjC: However, don't match an Objective-C method name which
 	 may have a '+' or '-' succeeded by a '['.  */
-      if (last_displayed_sal_is_valid ()
-	  && (!cursal.symtab
-	      || ((strchr ("+-", (*address)[0]) != NULL)
-		  && ((*address)[1] != '['))))
-	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
-			  get_last_displayed_symtab (),
-			  get_last_displayed_line (),
-			  canonical, NULL, NULL);
+      if (els != NULL)
+	{
+	  if (last_displayed_sal_is_valid ())
+	    decode_explicit_linespec (els, DECODE_LINE_FUNFIRSTLINE,
+                                      get_last_displayed_symtab (),
+                                      get_last_displayed_line (),
+                                      canonical, NULL, NULL);
+	  else
+	    decode_explicit_linespec (els, DECODE_LINE_FUNFIRSTLINE,
+                                      NULL, 0, canonical,
+                                      NULL, NULL);
+	}
       else
-	decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
-			  cursal.symtab, cursal.line, canonical, NULL, NULL);
+	{
+	  if (last_displayed_sal_is_valid ()
+	      && (!cursal.symtab
+		  || ((strchr ("+-", (*address)[0]) != NULL)
+		      && ((*address)[1] != '['))))
+	    decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
+			      get_last_displayed_symtab (),
+			      get_last_displayed_line (),
+			      canonical, NULL, NULL);
+	  else
+	    decode_line_full (address, DECODE_LINE_FUNFIRSTLINE,
+                              cursal.symtab, cursal.line, canonical,
+                              NULL, NULL);
+	}
     }
 }
 
@@ -9536,6 +9575,8 @@ create_breakpoint_1 (struct gdbarch *gdbarch,
 
       init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
 
+      if (canonical->explicit != NULL)
+	b->explicit = copy_explicit_linespec (canonical->explicit);
       if (canonical->addr_string)
 	b->addr_string = xstrdup (canonical->addr_string);
       if (parse_condition_and_thread)
@@ -9636,10 +9677,12 @@ create_breakpoint (struct gdbarch *gdbarch, explicit_linespec *els,
 
   back_to = make_cleanup_destroy_linespec_result (&canonical);
 
-  if (canonical.addr_string == NULL)
+  if (canonical.explicit == NULL)
     {
       if (addr_start)
 	canonical.addr_string = xstrdup (addr_start);
+      if (els != NULL)
+	canonical.explicit = copy_explicit_linespec (els);
     }
 
   result = create_breakpoint_1 (gdbarch, &canonical, arg, cond_string,
@@ -9666,7 +9709,9 @@ break_command_1 (char *arg, int flag, int from_tty)
   enum bptype type_wanted = (flag & BP_HARDWAREFLAG
 			     ? bp_hardware_breakpoint
 			     : bp_breakpoint);
+  explicit_linespec *els;
   struct breakpoint_ops *ops;
+  struct cleanup *back_to;
   const char *arg_cp = arg;
 
   /* Matching breakpoints on probes.  */
@@ -9675,8 +9720,11 @@ break_command_1 (char *arg, int flag, int from_tty)
   else
     ops = &bkpt_breakpoint_ops;
 
+  /* Check for an explicit linespec.  */
+  els = string_to_explicit_linespec (&arg);
+  back_to = make_cleanup (free_explicit_linespec, els);
   create_breakpoint (get_current_arch (),
-		     NULL, arg,
+		     els, arg,
 		     NULL, 0, NULL, 1 /* parse arg */,
 		     tempflag, type_wanted,
 		     0 /* Ignore count */,
@@ -9686,6 +9734,7 @@ break_command_1 (char *arg, int flag, int from_tty)
 		     1 /* enabled */,
 		     0 /* internal */,
 		     0);
+  do_cleanups (back_to);
 }
 
 /* Helper function for break_command_1 and disassemble_command.  */
@@ -12639,7 +12688,17 @@ say_where (struct breakpoint *b)
      single string.  */
   if (b->loc == NULL)
     {
-      printf_filtered (_(" (%s) pending."), b->addr_string);
+      char *where = b->addr_string;
+      struct cleanup *free_where = make_cleanup (null_cleanup, NULL);
+
+      if (b->explicit != NULL)
+	{
+	  where = explicit_linespec_to_string (b->explicit, b->addr_string);
+	  make_cleanup (xfree, where);
+	}
+
+      printf_filtered (_(" (%s) pending."), where);
+      do_cleanups (free_where);
     }
   else
     {
@@ -12702,6 +12761,7 @@ base_breakpoint_dtor (struct breakpoint *self)
   xfree (self->addr_string);
   xfree (self->filter);
   xfree (self->addr_string_range_end);
+  free_explicit_linespec (self->explicit);
 }
 
 static struct bp_location *
@@ -12854,7 +12914,7 @@ static void
 bkpt_re_set (struct breakpoint *b)
 {
   /* FIXME: is this still reachable?  */
-  if (b->addr_string == NULL)
+  if (b->addr_string == NULL && b->explicit == NULL)
     {
       /* Anything without a string can't be re-set.  */
       delete_breakpoint (b);
@@ -13237,6 +13297,9 @@ bkpt_probe_create_sals_from_address (explicit_linespec *els, char **arg,
 {
   struct linespec_sals lsal;
 
+  if (els != NULL)
+    explicit_linespec_unsupported (type_wanted);
+
   lsal.sals = parse_probes (arg, canonical);
 
   *copy_arg = xstrdup (canonical->addr_string);
@@ -13249,6 +13312,9 @@ static void
 bkpt_probe_decode_linespec (struct breakpoint *b, explicit_linespec *els,
 			    char **s, struct symtabs_and_lines *sals)
 {
+  if (els != NULL)
+    explicit_linespec_unsupported (b->type);
+
   *sals = parse_probes (s, NULL);
   if (!sals->sals)
     error (_("probe not found"));
@@ -13461,7 +13527,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 
       tp = XCNEW (struct tracepoint);
       init_breakpoint_sal (&tp->base, gdbarch, expanded,
-			   NULL, addr_string, NULL,
+			   canonical->explicit, addr_string, NULL,
 			   cond_string, extra_string,
 			   type_wanted, disposition,
 			   thread, task, ignore_count, ops,
@@ -13487,6 +13553,9 @@ strace_marker_decode_linespec (struct breakpoint *b, explicit_linespec *els,
 {
   struct tracepoint *tp = (struct tracepoint *) b;
 
+  if (els != NULL)
+    explicit_linespec_unsupported (b->type);
+
   *sals = decode_static_tracepoint_spec (s);
   if (sals->nelts > tp->static_trace_marker_id_idx)
     {
@@ -14127,7 +14196,7 @@ breakpoint_re_set_default (struct breakpoint *b)
   struct symtabs_and_lines expanded = {0};
   struct symtabs_and_lines expanded_end = {0};
 
-  sals = addr_string_to_sals (b, NULL, b->addr_string, &found);
+  sals = addr_string_to_sals (b, b->explicit, b->addr_string, &found);
 
   if (found)
     {
@@ -14137,7 +14206,7 @@ breakpoint_re_set_default (struct breakpoint *b)
 
   if (b->addr_string_range_end)
     {
-      sals_end = addr_string_to_sals (b, NULL, b->addr_string_range_end,
+      sals_end = addr_string_to_sals (b, b->explicit, b->addr_string_range_end,
 				      &found);
       if (found)
 	{
@@ -14196,10 +14265,15 @@ decode_linespec_default (struct breakpoint *b, explicit_linespec *els,
   struct linespec_result canonical;
 
   init_linespec_result (&canonical);
-  decode_line_full (s, DECODE_LINE_FUNFIRSTLINE,
-		    (struct symtab *) NULL, 0,
-		    &canonical, multiple_symbols_all,
-		    b->filter);
+  if (els == NULL)
+    decode_line_full (s, DECODE_LINE_FUNFIRSTLINE,
+		      (struct symtab *) NULL, 0,
+		      &canonical, multiple_symbols_all,
+		      b->filter);
+  else
+    decode_explicit_linespec (els, DECODE_LINE_FUNFIRSTLINE,
+			      NULL, 0, &canonical, multiple_symbols_all,
+			      b->filter);
 
   /* We should get 0 or 1 resulting SALs.  */
   gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 43be84a..3212f4f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -683,6 +683,11 @@ struct breakpoint
     /* String we used to set the breakpoint (malloc'd).  */
     char *addr_string;
 
+    /* The explicit linespec used to set the breakpoint (malloc'd).
+       This may be computed by decode_line_full/decode_explicit_linespec
+       or set by the user.  */
+    struct explicit_linespec *explicit;
+
     /* The filter that should be passed to decode_line_full when
        re-setting this breakpoint.  This may be NULL, but otherwise is
        allocated with xmalloc.  */
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 2b84515..fcbf3dd 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -1664,9 +1664,14 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
   if (!state->canonical)
     return;
 
+  state->canonical->explicit = new_explicit_linespec ();
+
   /* Shortcut expressions, which can only appear by themselves.  */
   if (ls->expression != NULL)
-    state->canonical->addr_string = xstrdup (ls->expression);
+    {
+      state->canonical->addr_string = xstrdup (ls->expression);
+      state->canonical->explicit->expression = xstrdup (ls->expression);
+    }
   else
     {
       struct ui_file *buf;
@@ -1676,6 +1681,8 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
       if (ls->source_filename)
 	{
 	  fputs_unfiltered (ls->source_filename, buf);
+	  state->canonical->explicit->source_filename
+	    = xstrdup (ls->source_filename);
 	  need_colon = 1;
 	}
 
@@ -1684,6 +1691,8 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 	  if (need_colon)
 	    fputc_unfiltered (':', buf);
 	  fputs_unfiltered (ls->function_name, buf);
+	  state->canonical->explicit->function_name
+	    = xstrdup (ls->function_name);
 	  need_colon = 1;
 	}
 
@@ -1706,6 +1715,7 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 	    }
 
 	  fputs_unfiltered (ls->label_name, buf);
+	  state->canonical->explicit->label_name = xstrdup (ls->label_name);
 	  need_colon = 1;
 	  state->canonical->special_display = 1;
 	}
@@ -1714,11 +1724,13 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
 	{
 	  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);
+	  state->canonical->explicit->offset
+	    = xstrprintf ("%s%d",
+			  (ls->line_offset.sign == LINE_OFFSET_NONE ? ""
+			   : (ls->line_offset.sign
+			      == LINE_OFFSET_PLUS ? "+" : "-")),
+			  ls->line_offset.offset);
+	  fputs_filtered (state->canonical->explicit->offset, buf);
 	}
 
       state->canonical->addr_string = ui_file_xstrdup (buf, NULL);
@@ -2385,6 +2397,125 @@ decode_line_full (char **argptr, int flags,
   do_cleanups (cleanups);
 }
 
+/* A parsing function for explicit linespecs.  */
+
+static struct symtabs_and_lines
+parse_explicit_linespec (linespec_parser *parser, void *data)
+{
+  VEC (symbolp) *symbols, *labels;
+  VEC (minsym_and_objfile_d) *minimal_symbols;
+  explicit_linespec *els = (explicit_linespec *) data;
+
+  if (els->expression != NULL)
+    {
+      char *copy = xstrdup (els->expression);
+      struct cleanup *cleanup = make_cleanup (xfree, copy);
+
+      /* Convert the expression to a PC and save the result.  */
+      PARSER_RESULT (parser)->expr_pc = linespec_expression_to_pc (&copy);
+      PARSER_RESULT (parser)->expression = xstrdup (els->expression);
+      do_cleanups (cleanup);
+    }
+  else
+    {
+      if (els->source_filename != NULL)
+	{
+	  volatile struct gdb_exception except;
+
+	  TRY_CATCH (except, RETURN_MASK_ERROR)
+	    {
+	      PARSER_RESULT (parser)->file_symtabs
+		= symtabs_from_filename (els->source_filename);
+	    }
+
+	  if (except.reason < 0
+	      || PARSER_RESULT (parser)->file_symtabs == NULL)
+	    source_file_not_found_error (els->source_filename);
+
+	  /* Save the source filename in the parser's result.  */
+	  PARSER_RESULT (parser)->source_filename
+	    = xstrdup (els->source_filename);
+	}
+      else
+	{
+	  /* A NULL entry means to use the default symtab.  */
+	  VEC_safe_push (symtab_p, PARSER_RESULT (parser)->file_symtabs, NULL);
+	}
+
+      if (els->function_name != NULL)
+	{
+	  find_linespec_symbols (PARSER_STATE (parser),
+				 PARSER_RESULT (parser)->file_symtabs,
+				 els->function_name, &symbols,
+				 &minimal_symbols);
+
+	  if (symbols == NULL && minimal_symbols == NULL)
+	    symbol_not_found_error (els->function_name,
+				    PARSER_RESULT (parser)->source_filename);
+
+	  PARSER_RESULT (parser)->function_name = xstrdup (els->function_name);
+	  PARSER_RESULT (parser)->function_symbols = symbols;
+	  PARSER_RESULT (parser)->minimal_symbols = minimal_symbols;
+	}
+
+      if (els->label_name != NULL)
+	{
+	  symbols = NULL;
+	  labels = find_label_symbols (PARSER_STATE (parser),
+				       PARSER_RESULT (parser)->function_symbols,
+				       &symbols, els->label_name);
+
+	  if (labels == NULL)
+	    undefined_label_error (PARSER_RESULT (parser)->function_name,
+				   els->label_name);
+
+	  PARSER_RESULT (parser)->label_name = xstrdup (els->label_name);
+	  PARSER_RESULT (parser)->labels.label_symbols = labels;
+	  PARSER_RESULT (parser)->labels.function_symbols = symbols;
+	}
+
+      if (els->offset != NULL)
+	PARSER_RESULT (parser)->line_offset
+	  = linespec_parse_line_offset (els->offset);
+
+      /* One special error check: If SOURCE_FILENAME was given without
+	 OFFSET, FUNCTION_NAME, or LABEL_NAME, issue an error.  */
+      if (PARSER_RESULT (parser)->source_filename != NULL
+	  && PARSER_RESULT (parser)->function_name == NULL
+	  && PARSER_RESULT (parser)->label_name == NULL
+	  && PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
+	error (_("Source filename requires function, label, or offset."));
+    }
+
+  /* Convert the "parse" to SALs.  */
+  return convert_linespec_to_sals (PARSER_STATE (parser),
+				   PARSER_RESULT (parser));
+}
+
+/* Decode the explicit linespec in ELS.  The other parameters are
+   the same as decode_line_full.  */
+
+void
+decode_explicit_linespec (explicit_linespec *els, int flags,
+			  struct symtab *default_symtab,
+			  int default_line, struct linespec_result *canonical,
+			  const char *select_mode,
+			  const char *filter)
+{
+  linespec_parser parser;
+  struct cleanup *cleanups;
+
+  gdb_assert (canonical != NULL);
+  gdb_assert ((flags & DECODE_LINE_LIST_MODE) == 0);
+
+  linespec_parser_new (&parser, parse_explicit_linespec, flags,
+		       current_language, default_symtab,
+		       default_line, canonical);
+  cleanups = make_cleanup (linespec_parser_delete, &parser);
+  do_decode_line (&parser, els, select_mode, filter);
+  do_cleanups (cleanups);
+}
+
 /* See linespec.h.  */
 
 struct symtabs_and_lines
@@ -2487,7 +2618,8 @@ linespec_expression_to_pc (char **exp_ptr)
     throw_error (NOT_FOUND_ERROR, _("cannot evaluate expressions while "
 				    "program space is in startup"));
 
-  (*exp_ptr)++;
+  if (**exp_ptr == '*')
+    (*exp_ptr)++;
   return value_as_address (parse_to_comma_and_eval (exp_ptr));
 }
 
@@ -3573,6 +3705,7 @@ destroy_linespec_result (struct linespec_result *ls)
   struct linespec_sals *lsal;
 
   xfree (ls->addr_string);
+  free_explicit_linespec (ls->explicit);
   for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
     {
       xfree (lsal->canonical);
@@ -3596,3 +3729,299 @@ make_cleanup_destroy_linespec_result (struct linespec_result *ls)
 {
   return make_cleanup (cleanup_linespec_result, ls);
 }
+
+/* Allocate and initialize a new explicit_linespec.  */
+
+explicit_linespec *
+new_explicit_linespec (void)
+{
+  return XCNEW (explicit_linespec);
+}
+
+/* Free the explicit_linespec represented by OBJ.  */
+
+void
+free_explicit_linespec (void *obj)
+{
+  explicit_linespec *els = (explicit_linespec *) obj;
+
+  if (els != NULL)
+    {
+      xfree ((char *) els->source_filename);
+      xfree ((char *) els->function_name);
+      xfree ((char *) els->label_name);
+      xfree ((char *) els->offset);
+      xfree ((char *) els->expression);
+      xfree (els);
+    }
+}
+
+/* A lexer for explicit linespecs. This function will advance INP past
+   any strings that it returns.  Returns a malloc'd copy of the
+   lexed string or NULL if no lexing was done.  */
+
+static char *
+explicit_lex_one (char **inp)
+{
+  char *start = *inp;
+
+  if (*start != '\0')
+    {
+      int lexing_number = 0;
+
+      /* If quoted, skip to the ending quote.  */
+      if (strchr (linespec_quote_characters, *start))
+	{
+	  char quote_char = *start;
+
+	  /* If the input is not an ada operator, skip to the matching
+	     closing quote and return the string.  */
+	  if (!(current_language->la_language == language_ada
+		&& quote_char == '\"' && is_ada_operator (start)))
+	    {
+	      const char *end = skip_quote_char (start + 1, quote_char);
+
+	      if (end == NULL)
+		error (_("unmatched quote"));
+	      *inp = (char *) end + 1;
+	      return savestring (start + 1, *inp - start - 2);
+	    }
+	}
+
+      /* Are we lexing a number?  */
+      if ((start[0] == '-' || start[0] == '+')
+	  && start[1] && isdigit (start[1]))
+	{
+	  /* The input is a relative offset.  */
+	  lexing_number = 1;
+
+	  /* Skip the +/-.  */
+	  ++(*inp);
+	}
+      else if (isdigit (*start))
+	lexing_number = 1;
+
+      /* If the input starts with '-', the string ends with the next
+	 whitespace.  */
+      if (*start == '-')
+	{
+	  while ((*inp)[0] && !isspace ((*inp)[0]))
+	    ++(*inp);
+	}
+      /* If lexing a number, stop at the first non-digit character.  */
+      else if (lexing_number)
+	{
+	  while ((*inp)[0] && isdigit ((*inp)[0]))
+	    ++(*inp);
+	}
+      else
+	{
+	  /* Otherwise, stop at the next occurrence of "SPACE -", '\0', or
+	     keyword.  */
+	  while ((*inp)[0]
+		 && !(isspace ((*inp)[0])
+		      && ((*inp)[1] == '-'
+			  || linespec_lexer_lex_keyword (&(*inp)[1]))))
+	    ++(*inp);
+	}
+    }
+
+  if (*inp - start > 0)
+    return savestring (start, *inp - start);
+
+  return NULL;
+}
+
+/* Attempt to convert the address string in *ARGP into an explicit_linespec.
+   Returns the explicit linespec (which must be free'd by the caller) and
+   advances ARGP over all processed input. Returns NULL if *ARGP does
+   not describe an explicit linespec.
+
+   This function may call error() if the *ARGP looks like properly formed
+   input, e.g., if it is called with missing argument parameters or
+   invalid options.  */
+
+explicit_linespec *
+string_to_explicit_linespec (char **argp)
+{
+
+  /* It is assumed that linespecs beginning with '-' and a non-digit
+     character is an explicit linespec.  */
+  if (argp != NULL && *argp != NULL)
+    {
+      const char *copy = *argp;
+
+      if (probe_linespec_to_ops (&copy) != NULL)
+	{
+	  /* Explicit linespecs with probes is not supported.  */
+	  return NULL;
+	}
+
+      if ((*argp)[0] == '-' && isalpha ((*argp)[1]))
+	{
+	  explicit_linespec *els;
+	  struct cleanup *cleanup;
+
+	  els = new_explicit_linespec ();
+	  cleanup = make_cleanup (free_explicit_linespec, els);
+
+	  /* Process option/argument pairs.  */
+	  while ((*argp)[0] != '\0')
+	    {
+	      int len;
+	      char *opt, *oarg, *start;
+	      struct cleanup *inner;
+
+	      /* If *ARGP starts with a keyword, stop processing
+		 options.  */
+	      if (linespec_lexer_lex_keyword (*argp) != NULL)
+		break;
+
+	      /* Mark the start of the string in case we need to rewind.  */
+	      start = *argp;
+
+	      /* Get the option string.  */
+	      opt = explicit_lex_one (argp);
+	      inner = make_cleanup (xfree, opt);
+
+	      /* Skip any whitespace.  */
+	      *argp = skip_spaces (*argp);
+
+	      /* Get the argument string.  */
+	      oarg = explicit_lex_one (argp);
+	      make_cleanup (xfree, oarg);
+
+	      /* Skip any whitespace.  */
+	      *argp = skip_spaces (*argp);
+
+	      /* Use the length of the option to allow abbreviations.  */
+	      len = strlen (opt);
+
+	      /* All options have a required argument.  */
+	      if (strncmp (opt, "-source", len) == 0)
+		els->source_filename = oarg;
+	      else if (strncmp (opt, "-function", len) == 0)
+		els->function_name = oarg;
+	      else if (strncmp (opt, "-label", len) == 0)
+		els->label_name = oarg;
+	      else if (strncmp (opt, "-offset", len) == 0)
+		els->offset = oarg;
+	      else if (strncmp (opt, "-address", len) == 0)
+		els->expression = oarg;
+	      /* Only emit an "invalid argument" error for options
+		 that look like option strings.  */
+	      else if (opt[0] == '-' && !isdigit (opt[1]))
+		error (_("invalid linespec argument, \"%s\""), opt);
+	      else
+		{
+		  /* Trailing garbage.  This will be handled by
+		     one of the callers.  */
+		  *argp = start;
+		  break;
+		}
+
+	      /* It's a little lame to error after the fact, but in this
+		 case, it provides a much better user experience to issue
+		 the "invalid linespec argument" error before any missing
+		 argument error.  */
+	      if (oarg == NULL)
+		error (_("missing argument for \"%s\""), opt);
+
+	      /* The option/argument pair was successfully processed,
+		 that memory now belongs to the explicit_linespec.  */
+	      discard_cleanups (inner);
+	    }
+
+	  /* A valid explicit linespec was constructed.  */
+	  discard_cleanups (cleanup);
+	  return els;
+	}
+    }
+
+  /* Not an explicit linespec.  */
+  return NULL;
+}
+
+/* Deep copy the explicit linespec given by SRC and return
+   the copy.  */
+
+explicit_linespec *
+copy_explicit_linespec (explicit_linespec *src)
+{
+  explicit_linespec *copy;
+
+  copy = XCNEW (explicit_linespec);
+#define STRDUP_IF(MBR)				\
+  do {						\
+    if (src->MBR != NULL)			\
+      copy->MBR = xstrdup (src->MBR);		\
+  }						\
+  while (0)
+  STRDUP_IF (source_filename);
+  STRDUP_IF (function_name);
+  STRDUP_IF (label_name);
+  STRDUP_IF (offset);
+  STRDUP_IF (expression);
+#undef STRDUP_IF
+  return copy;
+}
+
+/* Return a string representation of the explicit linespec
+   ELS, appending ARG (conditional, thread, task).
+   The result is malloc'd and must be free'd by the caller.  */
+
+char *
+explicit_linespec_to_string (explicit_linespec *els, const char *arg)
+{
+  char *string;
+  struct ui_file *buf;
+  int need_colon = 0;
+
+  buf = mem_fileopen ();
+
+  if (els->expression)
+    fprintf_unfiltered (buf, "*%s", els->expression);
+  else
+    {
+      if (els->source_filename != NULL)
+	{
+	  fputs_unfiltered (els->source_filename, buf);
+	  need_colon = 1;
+	}
+
+      if (els->function_name != NULL)
+	{
+	  if (need_colon)
+	    fputc_unfiltered (':', buf);
+	  fputs_unfiltered (els->function_name, buf);
+	  need_colon = 1;
+	}
+
+      if (els->label_name != NULL)
+	{
+	  if (need_colon)
+	    fputc_unfiltered (':', buf);
+	  fputs_unfiltered (els->label_name, buf);
+	  need_colon = 1;
+	}
+
+      if (els->offset != NULL)
+	{
+	  if (need_colon)
+	    fputc_unfiltered (':', buf);
+	  fputs_unfiltered (els->offset, buf);
+	}
+    }
+
+  /* Append any non-explicit text added by user.  */
+  if (arg != NULL)
+    {
+      fputc_unfiltered (' ', buf);
+      fputs_unfiltered (arg, buf);
+    }
+
+  /* Covert to a string a return.  */
+  string = ui_file_xstrdup (buf, NULL);
+  ui_file_delete (buf);
+  return string;
+}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 51b111b..95da829 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -96,6 +96,10 @@ struct linespec_result
      by the user.  This will be freed by destroy_linespec_result.  */
   char *addr_string;
 
+  /* The explicit linespec returned by the parser or NULL if the
+     input could not be parsed.  */
+  struct explicit_linespec *explicit;
+
   /* The sals.  The vector will be freed by
      destroy_linespec_result.  */
   VEC (linespec_sals) *sals;
@@ -114,6 +118,27 @@ extern void destroy_linespec_result (struct linespec_result *);
 extern struct cleanup *
         make_cleanup_destroy_linespec_result (struct linespec_result *);
 
+/* Allocate and initialize a new explicit_linespec.  */
+extern explicit_linespec *new_explicit_linespec (void);
+
+/* Free the explicit linespec represented by OBJ.  */
+extern void free_explicit_linespec (void *obj);
+
+/* Copy the given explicit linespec.  Free memory with
+   free_explicit_linespec.  */
+extern explicit_linespec *copy_explicit_linespec (explicit_linespec *src);
+
+/* Return a string representation of the explicit linespec ELS,
+   appending ARG (conditional/thread/task).  */
+extern char *explicit_linespec_to_string (explicit_linespec *els,
+					  const char *arg);
+
+/* Attempt to convert the string in *ARGP into an explicit_linespec.
+   Returns the explicit linespec (which must be free'd by the caller) and
+   advacnes ARGP over all processed input.  Returns NULL if *ARGP does
+   not describe an explicit linespec.  */
+explicit_linespec *string_to_explicit_linespec (char **argp);
+
 /* Decode a linespec using the provided default symtab and line.  */
 
 extern struct symtabs_and_lines
@@ -162,6 +187,13 @@ extern void decode_line_full (char **argptr, int flags,
 			      const char *select_mode,
 			      const char *filter);
 
+extern void decode_explicit_linespec (struct explicit_linespec *els, int flags,
+				      struct symtab *default_symtab,
+				      int default_line,
+				      struct linespec_result *canonical,
+				      const char *select_mode,
+				      const char *filter);
+
 /* Given a string, return the line specified by it, using the current
    source symtab and line as defaults.
    This is for commands like "list" and "breakpoint".  */
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 52ea90c..b96074d 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -23,6 +23,7 @@
 #include "ui-out.h"
 #include "mi-out.h"
 #include "breakpoint.h"
+#include "linespec.h"
 #include "gdb_string.h"
 #include "mi-getopt.h"
 #include "gdb.h"
@@ -74,14 +75,18 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
   int pending = 0;
   int enabled = 1;
   int tracepoint = 0;
+  int explicit = 0;
   struct cleanup *back_to;
   enum bptype type_wanted;
+  explicit_linespec *els;
 
   enum opt
     {
       HARDWARE_OPT, TEMP_OPT, CONDITION_OPT,
       IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT,
       TRACEPOINT_OPT,
+      EXPLICIT_EXPR_OPT, EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT,
+      EXPLICIT_LABEL_OPT, EXPLICIT_OFFSET_OPT
     };
   static const struct mi_opt opts[] =
   {
@@ -93,6 +98,11 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
     {"f", PENDING_OPT, 0},
     {"d", DISABLE_OPT, 0},
     {"a", TRACEPOINT_OPT, 0},
+    {"e", EXPLICIT_EXPR_OPT, 1},
+    {"s", EXPLICIT_SOURCE_OPT, 1},
+    {"m", EXPLICIT_FUNC_OPT, 1},
+    {"l", EXPLICIT_LABEL_OPT, 1},
+    {"o", EXPLICIT_OFFSET_OPT, 1},
     { 0, 0, 0 }
   };
 
@@ -101,6 +111,8 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
   int oind = 0;
   char *oarg;
 
+  els = new_explicit_linespec ();
+  back_to = make_cleanup (free_explicit_linespec, els);
   while (1)
     {
       int opt = mi_getopt ("-break-insert", argc, argv,
@@ -133,14 +145,46 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
 	case TRACEPOINT_OPT:
 	  tracepoint = 1;
 	  break;
+	case EXPLICIT_EXPR_OPT:
+	  explicit = 1;
+	  els->expression = xstrdup (oarg);
+	  break;
+	case EXPLICIT_SOURCE_OPT:
+	  explicit = 1;
+	  els->source_filename = xstrdup (oarg);
+	  break;
+	case EXPLICIT_FUNC_OPT:
+	  explicit = 1;
+	  els->function_name = xstrdup (oarg);
+	  break;
+	case EXPLICIT_LABEL_OPT:
+	  explicit = 1;
+	  els->label_name = xstrdup (oarg);
+	  break;
+	case EXPLICIT_OFFSET_OPT:
+	  explicit = 1;
+	  els->offset = xstrdup (oarg);
+	  break;
 	}
     }
 
-  if (oind >= argc)
+  if (oind >= argc && !explicit)
     error (_("-break-insert: Missing <location>"));
-  if (oind < argc - 1)
-    error (_("-break-insert: Garbage following <location>"));
-  address = argv[oind];
+  if (explicit)
+    {
+      if (oind < argc)
+	error (_("-break-insert: Garbage following explicit linesepc"));
+    }
+  else
+    {
+      if (oind < argc - 1)
+	error (_("-break-insert: Garbage following <location>"));
+      address = argv[oind];
+
+      /* An explicit linespec was not specified -- reset ELS to NULL.
+	 [It will be free'd in a cleanup later.]  */
+      els = NULL;
+    }
 
   /* Now we have what we need, let's insert the breakpoint!  */
   if (! mi_breakpoint_observers_installed)
@@ -149,7 +193,7 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
       mi_breakpoint_observers_installed = 1;
     }
 
-  back_to = make_cleanup_restore_integer (&mi_can_breakpoint_notify);
+  make_cleanup_restore_integer (&mi_can_breakpoint_notify);
   mi_can_breakpoint_notify = 1;
 
   /* Note that to request a fast tracepoint, the client uses the
@@ -163,7 +207,7 @@ mi_cmd_break_insert (char *command, char **argv, int argc)
 		 ? (hardware ? bp_fast_tracepoint : bp_tracepoint)
 		 : (hardware ? bp_hardware_breakpoint : bp_breakpoint));
 
-  create_breakpoint (get_current_arch (), NULL, address, condition, thread,
+  create_breakpoint (get_current_arch (), els, address, condition, thread,
 		     NULL /* extra_string  */,
 		     0 /* condition and thread are valid.  */,
 		     temp_p, type_wanted,

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