From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10141 invoked by alias); 27 Jul 2012 03:48:23 -0000 Received: (qmail 10131 invoked by uid 22791); 27 Jul 2012 03:48:19 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 27 Jul 2012 03:48:00 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q6R3lxTl007762 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 26 Jul 2012 23:47:59 -0400 Received: from valrhona.uglyboxes.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q6R3luuT020196 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 26 Jul 2012 23:47:57 -0400 Message-ID: <50120F6C.2000308@redhat.com> Date: Fri, 27 Jul 2012 03:48:00 -0000 From: Keith Seitz User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20120605 Thunderbird/13.0 MIME-Version: 1.0 To: "gdb-patches@sourceware.org ml" Subject: [RFA 3/5] Explicit linespecs - implementation Content-Type: multipart/mixed; boundary="------------040809020404000906090103" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-07/txt/msg00662.txt.bz2 This is a multi-part message in MIME format. --------------040809020404000906090103 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 2081 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 * 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. --------------040809020404000906090103 Content-Type: text/x-patch; name="els-explicit-linespec.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="els-explicit-linespec.patch" Content-length: 31854 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 ")); - if (oind < argc - 1) - error (_("-break-insert: Garbage following ")); - 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 ")); + 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, --------------040809020404000906090103--