* [RFA 3/5] Explicit linespecs - implementation
@ 2012-07-27 3:48 Keith Seitz
2012-07-27 4:31 ` Sergio Durigan Junior
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Keith Seitz @ 2012-07-27 3:48 UTC (permalink / raw)
To: gdb-patches@sourceware.org ml
[-- Attachment #1: Type: text/plain, Size: 2081 bytes --]
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.
[-- Attachment #2: els-explicit-linespec.patch --]
[-- Type: text/x-patch, Size: 31854 bytes --]
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 (©);
+ 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 (©) != 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,
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFA 3/5] Explicit linespecs - implementation
2012-07-27 3:48 [RFA 3/5] Explicit linespecs - implementation Keith Seitz
@ 2012-07-27 4:31 ` Sergio Durigan Junior
2012-07-30 15:59 ` Jan Kratochvil
2012-08-17 19:00 ` Tom Tromey
2 siblings, 0 replies; 4+ messages in thread
From: Sergio Durigan Junior @ 2012-07-27 4:31 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches@sourceware.org ml
On Friday, July 27 2012, Keith Seitz wrote:
> 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?
Not really a review, but a nitpicking instead.
> 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.
^^^^^^^^
"linespec".
> 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);
There should be a space between the comment and the function prototype.
Also, the comments are in both .c and .h, and I believe you could just
leave them in one of these files.
> /* 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);
Missing comment.
> 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
> - 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"));
^^^^^^^^
"linespec".
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFA 3/5] Explicit linespecs - implementation
2012-07-27 3:48 [RFA 3/5] Explicit linespecs - implementation Keith Seitz
2012-07-27 4:31 ` Sergio Durigan Junior
@ 2012-07-30 15:59 ` Jan Kratochvil
2012-08-17 19:00 ` Tom Tromey
2 siblings, 0 replies; 4+ messages in thread
From: Jan Kratochvil @ 2012-07-30 15:59 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches@sourceware.org ml
On Fri, 27 Jul 2012 05:47:56 +0200, Keith Seitz wrote:
> Questions/comments/concerns?
This adds yet another way how to specify linespecs. Have you considered
removing the b->addr_string field completely? What are the reasons for
conditional, thread, task not being already parsed into struct
explicit_linespec? For example probes could also be in explicit_linespec.
I would see explicit_linespec as enum + union. "expression" would be already
one enum type, classical linespec other type, probe yet another type, maybe
some more.
This way explicit_linespec would be always non-NULL and addr_string would be no
longer passed along. Currently all the use of both explicit_linespec and
addr_string together seem error prone to me.
Thanks,
Jan
> 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;
const char *
> + 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);
Here you will need to use a different variable.
In fact it would be easier then to just call ui_out_field_string two times.
> + }
> +
> + 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));
Error should be a sentence, capital 'E', "is not".
> +}
> +
> /* 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);
I do not understand it much, using ADDR_START without ELS no longer makes
sense? Parameter ELS of create_breakpoint is undocumented.
> + 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);
> + }
Similar const vs. non-const comment like above.
> +
> + 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,
Just drop the cast (struct symtab *) (yes, it is just code move).
> + &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. */
It can be sometimes NULL. When? [maybe obsolete comment now after the top
discussion]
> + 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;
It is only a style but I would prefer moving them into their blocks where they
are used (even if they will have to be declared multiple times).
> + 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 (©);
> + 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)++;
This is not right:
(gdb) l 1
1 int main (void) { return 0; }
2 int (*a) (void) = main;
3 int (**b) (void) = &a;
(gdb) p a
$1 = (int (*)(void)) 0x4004ec <main>
(gdb) p b
$2 = (int (**)(void)) 0x601018 <a>
(gdb) break -address b
Breakpoint 1 at 0x601018
(gdb) break -address *b
Note: breakpoint 1 also set at pc 0x601018.
Breakpoint 2 at 0x601018
(gdb) break -address (*b)
Breakpoint 3 at 0x4004ec: file 12.c, line 1.
(gdb)
'*b' and '(*b)' should behave the same, they are not.
> 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)
Function does not modify the string itself, so it should be 'const char **'.
> +{
> + char *start = *inp;
> +
> + if (*start != '\0')
IMO rather return if (*start == '\0'), the function is needlessly indented
right now.
> + {
> + 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"));
It could print:
error (_("unmatched quote starting at: %s"), start);
> + *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)
> +{
> +
Excessive empty line.
> + /* 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 (©) != 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;
I do not see these options documented in "help break".
> + /* 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);
Errors should be a sentence.
> + 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);
Errors should be a sentence.
> +
> + /* 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)
A nitpick but this macro does not have GNU Coding Style.
> + STRDUP_IF (source_filename);
> + STRDUP_IF (function_name);
> + STRDUP_IF (label_name);
> + STRDUP_IF (offset);
> + STRDUP_IF (expression);
> +#undef STRDUP_IF
> + return copy;
> +}
[...]
struct breakpoint:
struct explicit_linespec *explicit;
init_breakpoint_sal:
explicit_linespec *els,
style: Couldn't you use uniformly either struct explicit_linespec or
explicit_linespec (IMO struct explicit_linespec as GDB is using struct) and
also to either els or explicit (IMO explicit), sometimes you use just
explicit but sometimes explicit_linespec (free_explicit_linespec), IMO just use
explicit_linespec everywhere, too many new names for me for a single
patch/feature.
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFA 3/5] Explicit linespecs - implementation
2012-07-27 3:48 [RFA 3/5] Explicit linespecs - implementation Keith Seitz
2012-07-27 4:31 ` Sergio Durigan Junior
2012-07-30 15:59 ` Jan Kratochvil
@ 2012-08-17 19:00 ` Tom Tromey
2 siblings, 0 replies; 4+ messages in thread
From: Tom Tromey @ 2012-08-17 19:00 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches@sourceware.org ml
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> Ok, so here's what everyone has been waiting for. This patch adds the
Keith> implementation of explicit linespecs, including CLI and MI support.
Thanks, Keith. I'm very encouraged by this project.
Keith> +/* Throw an exception for unsupported explicit linespec. */
Keith> +
Keith> +static void ATTRIBUTE_NORETURN
Keith> +explicit_linespec_unsupported (enum bptype type)
Keith> +{
Keith> + error (_("explicit linespec not supported for %s"), bptype_string (type));
I found it pretty hard to track through the code to find out under what
circumstances this can really be called. Is it really an error for
users? Or should it be an assertion?
Keith> + char *where = b->addr_string;
Keith> + struct cleanup *free_where = make_cleanup (null_cleanup, NULL);
Keith> +
Keith> + if (b->explicit != NULL)
Keith> + {
Keith> + where = explicit_linespec_to_string (b->explicit, b->addr_string);
Keith> + make_cleanup (xfree, where);
Keith> + }
Keith> +
Keith> + printf_filtered (_(" (%s) pending."), where);
Keith> + do_cleanups (free_where);
I think it is better for users to preserve what they typed, warts and
all, and just regurgitate that.
Once upon a time we did not do this for breakpoint conditions -- we
printed from the expression object instead. This turned out to be quite
confusing since you would enter:
cond 5 p == 0x2168bf0
and 'info b' would print
if p == 34996784
... which is hard to recognize as the same thing, more difficult to
search for, etc.
I think this also means that if the user enters an explicit linespec, it
will be shown as a normal linespec, which seems sub-optimal.
Keith> +static char *
Keith> +explicit_lex_one (char **inp)
[...]
Keith> + const char *end = skip_quote_char (start + 1, quote_char);
IIRC, skip_quote_char has a funny quoting style -- there's no way to
quote a quote.
I think for new code we ought to adopt a better convention, like what
buildargv does.
Keith> + /* Get the argument string. */
Keith> + oarg = explicit_lex_one (argp);
Keith> + make_cleanup (xfree, oarg);
[...]
Keith> + else if (strncmp (opt, "-address", len) == 0)
Keith> + els->expression = oarg;
This means that users will have to type:
break -address "complicated expression (\"string\")"
Note how the string has to be quoted.
That seems not very user-friendly.
It would be nicer to parse the expression after -address, but that has
other complications -- for one thing, it means that -address would have
to come last, since parsing expression is "funny".
I think that is the better tradeoff though, because reordering the
arguments is less painful than quoting expressions. Also I wonder
whether completion works in a quoted expression...
A nice follow-up patch would be to expose this to the Python breakpoint
constructor, say via keyword arguments.
Tom
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-08-17 19:00 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-27 3:48 [RFA 3/5] Explicit linespecs - implementation Keith Seitz
2012-07-27 4:31 ` Sergio Durigan Junior
2012-07-30 15:59 ` Jan Kratochvil
2012-08-17 19:00 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox