[RFA,6/9] Explicit locations v2 - Add explicit locations
Commit Message
This is an update to this patch to incorporate changes from reviews of
earlier patches.
Keith
Changes since last version:
- remove SAVE_SPEC stuff
- struct linespec: use struct explicit_location instead of
all those strings/line_offset.
- Add PARSER_EXPLICIT and use it where needed
- No need to "convert linespec to explicit" -- the parser
now builds an explicit location of the parsed result.
- move string constructions out of canonicalize_linespec and into
its own function
- update comments on grammar of linespecs: expr_spec is now
no longer considered a linespec.
- add explicit_to_string_internal and use it to implement
explicit_location_to_string/explicit_location_to_linespec
- new_explicit_location
- remove explicit_to_event_location
ChangeLog
2014-05-29 Keith Seitz <keiths@redhat.com>
* breakpoint.c (create_overlay_breakpoint): Convert linespec
into explicit location.
(create_longjmp_master_breakpoint): Likewise.
(create_std_terminate_master_breakpoint): Likewise.
(create_exception_master_breakpoint): Likewise.
(create_breakpoint): Update the SAVE_SPEC for explicit locations.
(update_static_tracepoint): Convert linespec into explicit location.
(location_to_sals): Save the string representation of the location
for pending locations which were resolved.
* linespec.c (enum offset_relative_sign): Move to location.h.
(struct line_offset): Likewise.
(struct linespec) <expression, expr_pc, source_filename>
<function_name, label_name, line_offset>: Replace with ...
<explicit>: ... this.
<is_linespec>: New member.
(PARSER_EXPLICIT): New accessor macro.
(undefined_label_error): New function.
(source_file_not_found_error): New function.
(linespec_parse_basic): The parser result is now an explicit location.
Use PARSER_EXPLICIT to access it.
Use undefined_label_error.
(canonicalize_linespec): Convert canonical linespec into explicit
location.
Move string representation of location to explicit_location_to_linespec
and use it and explicit_location_to_string to save string
representations of the canonical location.
(create_sals_line_offset): Use PARSER_EXPLICIT to access the parser's
explicit location result.
(convert_linespec_to_sals): `ls' contains an explicit location.
Update all references.
(convert_explicit_location_to_sals): New function.
(linespec_parse_basic): Use PARSER_EXPLICIT to access the parser
result's explicit location.
(linespec_state_constructor): Initialize is_linespec.
Use PARSER_EXPLICIT.
(linespec_parser_delete): Use PARSER_EXPLICIT to access the parser's
result.
(event_location_to_sals): For linespec locations, set is_linespec.
Handle explicit locations.
(decode_objc): 'ls' contains an explicit location now. Update all
references.
(symtabs_from_filename): Use source_file_not_found_error.
* location.c (initialize_explicit_location): New function.
(initialize_event_location): Initialize explicit locations.
(copy_event_location): Handle explicit locations.
(explicit_to_string_internal): New function; most of contents moved
from canonicalize_linespec.
(explicit_location_to_string): New function.
(explicit_location_to_linespec): New function.
(delete_event_location): Handle explicit locations.
(event_location_to_string_const): Likewise.
(event_location_empty_p): Likewise.
* location.h (enum offset_relative_sign): Move here from linespec.h.
(struct line_offset): Likewise.
(enum event_location_type): Add EXPLICIT_LOCATION.
(struct explicit_location): New structure.
(struct event_location.u) <explicit>: New member.
(EVENT_LOCATION_EXPLICIT): Define accessor macro.
(explicit_location_to_string): Declare.
(explicit_location_to_linespec): Declare.
(initialize_explicit_location): Declare.
Comments
Hi.
Several comments inline.
I still have patches 7,8,9 to go.
My plan is to get to them next week (fingers crossed, knock on wood,
and all that :-)).
Keith Seitz writes:
> This is an update to this patch to incorporate changes from reviews of
> earlier patches.
>
> Keith
>
> Changes since last version:
> - remove SAVE_SPEC stuff
> - struct linespec: use struct explicit_location instead of
> all those strings/line_offset.
> - Add PARSER_EXPLICIT and use it where needed
> - No need to "convert linespec to explicit" -- the parser
> now builds an explicit location of the parsed result.
> - move string constructions out of canonicalize_linespec and into
> its own function
> - update comments on grammar of linespecs: expr_spec is now
> no longer considered a linespec.
> - add explicit_to_string_internal and use it to implement
> explicit_location_to_string/explicit_location_to_linespec
> - new_explicit_location
> - remove explicit_to_event_location
>
> ChangeLog
> 2014-05-29 Keith Seitz <keiths@redhat.com>
>
> * breakpoint.c (create_overlay_breakpoint): Convert linespec
> into explicit location.
> (create_longjmp_master_breakpoint): Likewise.
> (create_std_terminate_master_breakpoint): Likewise.
> (create_exception_master_breakpoint): Likewise.
> (create_breakpoint): Update the SAVE_SPEC for explicit locations.
> (update_static_tracepoint): Convert linespec into explicit location.
> (location_to_sals): Save the string representation of the location
> for pending locations which were resolved.
> * linespec.c (enum offset_relative_sign): Move to location.h.
> (struct line_offset): Likewise.
> (struct linespec) <expression, expr_pc, source_filename>
> <function_name, label_name, line_offset>: Replace with ...
> <explicit>: ... this.
> <is_linespec>: New member.
> (PARSER_EXPLICIT): New accessor macro.
> (undefined_label_error): New function.
> (source_file_not_found_error): New function.
> (linespec_parse_basic): The parser result is now an explicit location.
> Use PARSER_EXPLICIT to access it.
> Use undefined_label_error.
> (canonicalize_linespec): Convert canonical linespec into explicit
> location.
> Move string representation of location to explicit_location_to_linespec
> and use it and explicit_location_to_string to save string
> representations of the canonical location.
> (create_sals_line_offset): Use PARSER_EXPLICIT to access the parser's
> explicit location result.
> (convert_linespec_to_sals): `ls' contains an explicit location.
> Update all references.
> (convert_explicit_location_to_sals): New function.
> (linespec_parse_basic): Use PARSER_EXPLICIT to access the parser
> result's explicit location.
> (linespec_state_constructor): Initialize is_linespec.
> Use PARSER_EXPLICIT.
> (linespec_parser_delete): Use PARSER_EXPLICIT to access the parser's
> result.
> (event_location_to_sals): For linespec locations, set is_linespec.
> Handle explicit locations.
> (decode_objc): 'ls' contains an explicit location now. Update all
> references.
> (symtabs_from_filename): Use source_file_not_found_error.
> * location.c (initialize_explicit_location): New function.
> (initialize_event_location): Initialize explicit locations.
> (copy_event_location): Handle explicit locations.
> (explicit_to_string_internal): New function; most of contents moved
> from canonicalize_linespec.
> (explicit_location_to_string): New function.
> (explicit_location_to_linespec): New function.
> (delete_event_location): Handle explicit locations.
> (event_location_to_string_const): Likewise.
> (event_location_empty_p): Likewise.
> * location.h (enum offset_relative_sign): Move here from linespec.h.
> (struct line_offset): Likewise.
> (enum event_location_type): Add EXPLICIT_LOCATION.
> (struct explicit_location): New structure.
> (struct event_location.u) <explicit>: New member.
> (EVENT_LOCATION_EXPLICIT): Define accessor macro.
> (explicit_location_to_string): Declare.
> (explicit_location_to_linespec): Declare.
> (initialize_explicit_location): Declare.
>
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 345b104..d8c74c0 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -3281,6 +3281,7 @@ create_overlay_event_breakpoint (void)
> struct breakpoint *b;
> struct breakpoint_objfile_data *bp_objfile_data;
> CORE_ADDR addr;
> + struct explicit_location explicit;
>
> bp_objfile_data = get_breakpoint_objfile_data (objfile);
>
> @@ -3305,7 +3306,9 @@ create_overlay_event_breakpoint (void)
> b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
> bp_overlay_event,
> &internal_breakpoint_ops);
> - b->location = new_linespec_location (func_name);
> + initialize_explicit_location (&explicit);
> + explicit.function_name = ASTRDUP (func_name);
> + b->location = new_explicit_location (&explicit);
>
> if (overlay_debugging == ovly_auto)
> {
> @@ -3402,6 +3405,7 @@ create_longjmp_master_breakpoint (void)
> struct breakpoint *b;
> const char *func_name;
> CORE_ADDR addr;
> + struct explicit_location explicit;
>
> if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
> continue;
> @@ -3424,7 +3428,9 @@ create_longjmp_master_breakpoint (void)
> addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
> b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
> &internal_breakpoint_ops);
> - b->location = new_linespec_location (func_name);
> + initialize_explicit_location (&explicit);
> + explicit.function_name = ASTRDUP (func_name);
> + b->location = new_explicit_location (&explicit);
> b->enable_state = bp_disabled;
> }
> }
> @@ -3455,6 +3461,7 @@ create_std_terminate_master_breakpoint (void)
> {
> struct breakpoint *b;
> struct breakpoint_objfile_data *bp_objfile_data;
> + struct explicit_location explicit;
>
> bp_objfile_data = get_breakpoint_objfile_data (objfile);
>
> @@ -3480,7 +3487,9 @@ create_std_terminate_master_breakpoint (void)
> b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
> bp_std_terminate_master,
> &internal_breakpoint_ops);
> - b->location = new_linespec_location (func_name);
> + initialize_explicit_location (&explicit);
> + explicit.function_name = ASTRDUP (func_name);
> + b->location = new_explicit_location (&explicit);
> b->enable_state = bp_disabled;
> }
> }
> @@ -3504,6 +3513,7 @@ create_exception_master_breakpoint (void)
> struct gdbarch *gdbarch;
> struct breakpoint_objfile_data *bp_objfile_data;
> CORE_ADDR addr;
> + struct explicit_location explicit;
>
> bp_objfile_data = get_breakpoint_objfile_data (objfile);
>
> @@ -3584,7 +3594,9 @@ create_exception_master_breakpoint (void)
> ¤t_target);
> b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
> &internal_breakpoint_ops);
> - b->location = new_linespec_location (func_name);
> + initialize_explicit_location (&explicit);
> + explicit.function_name = ASTRDUP (func_name);
> + b->location = new_explicit_location (&explicit);
> b->enable_state = bp_disabled;
> }
>
> @@ -10010,6 +10022,20 @@ create_breakpoint (struct gdbarch *gdbarch,
> init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
> b->location = copy_event_location (location);
>
> + /* If the location has a string representation,
> + save it to the breakpoint's location string cache, since this
> + may be used to save the breakpoint to a file. */
> + if (EVENT_LOCATION_TYPE (b->location) == EXPLICIT_LOCATION)
> + {
> + char *old = event_location_to_string_const (location);
> +
> + b->location->as_string
> + = xstrprintf ("%s%s%s", old,
> + (extra_string == NULL ? "" : " "),
> + (extra_string == NULL ? "" : extra_string));
Here's another case where a file outside of the event-location-specific code
is reaching into the internal implementation details of an event location.
Plus it's a bit confusing to do this:
b->location = copy_event_location (location);
and then change the as_string representation of the location we just copied,
but only for EXPLICIT_LOCATION. E.g., As the reader I'm left wondering
what happens to extra_string if the event location was a different kind.
Can you elaborate on what's going on here?
> + xfree (old);
> + }
> +
> if (parse_arg)
> b->cond_string = NULL;
> else
> @@ -10022,7 +10048,17 @@ create_breakpoint (struct gdbarch *gdbarch,
> }
> b->cond_string = cond_string;
> }
> - b->extra_string = NULL;
> +
> + /* For explicit locations, EXTRA_STRING may contain breakpoint
> + condition information. Make a private copy of this for the
> + breakpoint. */
The comment predicates itself on being specific to explicit locations,
but the code doesn't check for EXPLICIT_LOCATION.
Can you elaborate on what's going on here?
> + if (extra_string != NULL && *extra_string != '\0')
> + {
> + b->extra_string = xstrdup (extra_string);
> + make_cleanup (xfree, b->extra_string);
> + }
> + else
> + b->extra_string = NULL;
> b->ignore_count = ignore_count;
> b->disposition = tempflag ? disp_del : disp_donttouch;
> b->condition_not_parsed = 1;
> @@ -14212,6 +14248,7 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
> struct symbol *sym;
> struct static_tracepoint_marker *tpmarker;
> struct ui_out *uiout = current_uiout;
> + struct explicit_location explicit;
>
> tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
>
> @@ -14253,11 +14290,12 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
> b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
>
> delete_event_location (b->location);
> - b->location = new_linespec_location (NULL);
> - EVENT_LOCATION_LINESPEC (b->location)
> - = xstrprintf ("%s:%d",
> - symtab_to_filename_for_display (sal2.symtab),
> - b->loc->line_number);
> + initialize_explicit_location (&explicit);
> + explicit.source_filename
> + = ASTRDUP (symtab_to_filename_for_display (sal2.symtab));
> + explicit.line_offset.offset = b->loc->line_number;
> + explicit.line_offset.sign = LINE_OFFSET_NONE;
> + b->location = new_explicit_location (&explicit);
Hmmm, the name new_explicit_location is ambiguous.
Does it return an explicit_location* or an event_location* ?
I like the consistency with new_linespec_location, new_address_location, etc.
so I understand why it's the latter, though my first guess would be the former
(though that would be confusing given that we're passing it an
explicit_location*).
No need to change anything, just thinking out loud.
>
> /* Might be nice to check if function changed, and warn if
> so. */
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index deda86e..f141a86 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -66,73 +66,26 @@ typedef struct bound_minimal_symbol bound_minimal_symbol_d;
>
> DEF_VEC_O (bound_minimal_symbol_d);
>
> -/* An enumeration of possible signs for a line offset. */
> -enum offset_relative_sign
> -{
> - /* No sign */
> - LINE_OFFSET_NONE,
> -
> - /* A plus sign ("+") */
> - LINE_OFFSET_PLUS,
> -
> - /* A minus sign ("-") */
> - LINE_OFFSET_MINUS,
> -
> - /* A special "sign" for unspecified offset. */
> - LINE_OFFSET_UNKNOWN
> -};
> -
> -/* A line offset in a linespec. */
> -
> -struct line_offset
> -{
> - /* Line offset and any specified sign. */
> - int offset;
> - enum offset_relative_sign sign;
> -};
> -
> /* A linespec. Elements of this structure are filled in by a parser
> (either parse_linespec or some other function). The structure is
> then converted into SALs by convert_linespec_to_sals. */
>
> struct linespec
> {
> - /* An expression and the resulting PC. Specifying an expression
> - currently precludes the use of other members. */
> -
> - /* The expression entered by the user. */
> - const char *expression;
> -
> - /* The resulting PC expression derived from evaluating EXPRESSION. */
> - CORE_ADDR expr_pc;
> -
> - /* Any specified file symtabs. */
> -
> - /* The user-supplied source filename or NULL if none was specified. */
> - const char *source_filename;
> + /* An explicit location describing the SaLs. */
> + struct explicit_location explicit;
Does this read better to you? [here, and at all uses]
struct explicit_location location;
Dunno.
When I read "explicit" I'm left wondering "Does that mean there's an implicit
or some other possibility for the location that I have to think about?"
The struct definition is local to linespec.c so the scope of any confusion
is nicely confined, so I wouldn't make any change unless you think
it's worth it.
>
> /* The list of symtabs to search to which to limit the search. May not
> - be NULL. If SOURCE_FILENAME is NULL (no user-specified filename),
> - FILE_SYMTABS should contain one single NULL member. This will
> - cause the code to use the default symtab. */
> + be NULL. If explicit.SOURCE_FILENAME is NULL (no user-specified
> + filename), FILE_SYMTABS should contain one single NULL member. This
> + will cause the code to use the default symtab. */
> VEC (symtab_ptr) *file_symtabs;
>
> - /* The name of a function or method and any matching symbols. */
> -
> - /* The user-specified function name. If no function name was
> - supplied, this may be NULL. */
> - const char *function_name;
> -
> /* A list of matching function symbols and minimal symbols. Both lists
> may be NULL if no matching symbols were found. */
> VEC (symbolp) *function_symbols;
> VEC (bound_minimal_symbol_d) *minimal_symbols;
>
> - /* The name of a label and matching symbols. */
> -
> - /* The user-specified label name. */
> - const char *label_name;
> -
> /* A structure of matching label symbols and the corresponding
> function symbol in which the label was found. Both may be NULL
> or both must be non-NULL. */
> @@ -141,10 +94,6 @@ struct linespec
> VEC (symbolp) *label_symbols;
> VEC (symbolp) *function_symbols;
> } labels;
> -
> - /* Line offset. It may be LINE_OFFSET_UNKNOWN, meaning that no
> - offset was specified. */
> - struct line_offset line_offset;
> };
> typedef struct linespec *linespec_p;
>
> @@ -197,6 +146,9 @@ struct linespec_state
> /* This is a set of address_entry objects which is used to prevent
> duplicate symbols from being entered into the result. */
> htab_t addr_set;
> +
> + /* Are we building a linespec? */
> + int is_linespec;
> };
>
> /* This is a helper object that is used when collecting symbols into a
> @@ -307,6 +259,10 @@ struct ls_parser
> };
> typedef struct ls_parser linespec_parser;
>
> +/* A convenience macro for accessing the explicit location result of
> + the parser. */
> +#define PARSER_EXPLICIT(PPTR) (&PARSER_RESULT ((PPTR))->explicit)
> +
> /* Prototypes for local functions. */
>
> static void iterate_over_file_blocks (struct symtab *symtab,
> @@ -1550,6 +1506,29 @@ unexpected_linespec_error (linespec_parser *parser)
> token_type_strings[token.type]);
> }
>
> +/* Throw an undefined label error. */
> +
> +static void ATTRIBUTE_NORETURN
> +undefined_label_error (const char *function, const char *label)
> +{
> + if (function != NULL)
> + throw_error (NOT_FOUND_ERROR,
> + _("No label \"%s\" defined in function \"%s\"."),
> + label, function);
> + else
> + throw_error (NOT_FOUND_ERROR,
> + _("No label \"%s\" defined in current function."),
> + label);
> +}
> +
> +/* Throw a source file not found error. */
> +
> +static void ATTRIBUTE_NORETURN
> +source_file_not_found_error (const char *name)
> +{
> + throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
> +}
> +
> /* Parse and return a line offset in STRING. */
>
> static struct line_offset
> @@ -1596,7 +1575,7 @@ linespec_parse_basic (linespec_parser *parser)
> /* Record the line offset and get the next token. */
> name = copy_token_string (token);
> cleanup = make_cleanup (xfree, name);
> - PARSER_RESULT (parser)->line_offset = linespec_parse_line_offset (name);
> + PARSER_EXPLICIT (parser)->line_offset = linespec_parse_line_offset (name);
> do_cleanups (cleanup);
>
> /* Get the next token. */
> @@ -1633,7 +1612,7 @@ linespec_parse_basic (linespec_parser *parser)
> {
> PARSER_RESULT (parser)->function_symbols = symbols;
> PARSER_RESULT (parser)->minimal_symbols = minimal_symbols;
> - PARSER_RESULT (parser)->function_name = name;
> + PARSER_EXPLICIT (parser)->function_name = name;
> symbols = NULL;
> discard_cleanups (cleanup);
> }
> @@ -1647,7 +1626,7 @@ linespec_parse_basic (linespec_parser *parser)
> {
> PARSER_RESULT (parser)->labels.label_symbols = labels;
> PARSER_RESULT (parser)->labels.function_symbols = symbols;
> - PARSER_RESULT (parser)->label_name = name;
> + PARSER_EXPLICIT (parser)->label_name = name;
> symbols = NULL;
> discard_cleanups (cleanup);
> }
> @@ -1655,14 +1634,14 @@ linespec_parse_basic (linespec_parser *parser)
> && *LS_TOKEN_STOKEN (token).ptr == '$')
> {
> /* User specified a convenience variable or history value. */
> - PARSER_RESULT (parser)->line_offset
> + PARSER_EXPLICIT (parser)->line_offset
> = linespec_parse_variable (PARSER_STATE (parser), name);
>
> - if (PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
> + if (PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
> {
> /* The user-specified variable was not valid. Do not
> throw an error here. parse_linespec will do it for us. */
> - PARSER_RESULT (parser)->function_name = name;
> + PARSER_EXPLICIT (parser)->function_name = name;
> discard_cleanups (cleanup);
> return;
> }
> @@ -1677,7 +1656,7 @@ linespec_parse_basic (linespec_parser *parser)
> an error here. parse_linespec will do it for us. */
>
> /* Save a copy of the name we were trying to lookup. */
> - PARSER_RESULT (parser)->function_name = name;
> + PARSER_EXPLICIT (parser)->function_name = name;
> discard_cleanups (cleanup);
> return;
> }
> @@ -1697,7 +1676,7 @@ linespec_parse_basic (linespec_parser *parser)
> get the next token. */
> name = copy_token_string (token);
> cleanup = make_cleanup (xfree, name);
> - PARSER_RESULT (parser)->line_offset
> + PARSER_EXPLICIT (parser)->line_offset
> = linespec_parse_line_offset (name);
> do_cleanups (cleanup);
>
> @@ -1717,16 +1696,15 @@ linespec_parse_basic (linespec_parser *parser)
> {
> PARSER_RESULT (parser)->labels.label_symbols = labels;
> PARSER_RESULT (parser)->labels.function_symbols = symbols;
> - PARSER_RESULT (parser)->label_name = name;
> + PARSER_EXPLICIT (parser)->label_name = name;
> symbols = NULL;
> discard_cleanups (cleanup);
> }
> else
> {
> /* We don't know what it was, but it isn't a label. */
> - throw_error (NOT_FOUND_ERROR,
> - _("No label \"%s\" defined in function \"%s\"."),
> - name, PARSER_RESULT (parser)->function_name);
> + undefined_label_error (PARSER_EXPLICIT (parser)->function_name,
> + name);
> }
>
> /* Check for a line offset. */
> @@ -1744,7 +1722,7 @@ linespec_parse_basic (linespec_parser *parser)
> name = copy_token_string (token);
> cleanup = make_cleanup (xfree, name);
>
> - PARSER_RESULT (parser)->line_offset
> + PARSER_EXPLICIT (parser)->line_offset
> = linespec_parse_line_offset (name);
> do_cleanups (cleanup);
>
> @@ -1761,42 +1739,19 @@ linespec_parse_basic (linespec_parser *parser)
> }
>
> /* Canonicalize the linespec contained in LS. The result is saved into
> - STATE->canonical. */
> + STATE->canonical. This function handles both linespec and explicit
> + locations. */
>
> static void
> canonicalize_linespec (struct linespec_state *state, linespec_p ls)
> {
> - struct ui_file *buf;
> - int need_colon = 0;
> -
> /* If canonicalization was not requested, no need to do anything. */
> if (!state->canonical)
No requested change here.
I just wanted to note that here's a good example where
"if (state->canonical == NULL)" would be clearer.
At this point in my reading for half a second I wondered if canonical was
a boolean, and was confused because the function comment said the result
was stored there.
> return;
>
> - buf = mem_fileopen ();
> -
> - state->canonical->location = new_linespec_location (NULL);
> -
> - if (ls->source_filename)
> + if (ls->explicit.label_name)
> {
> - fputs_unfiltered (ls->source_filename, buf);
> - need_colon = 1;
> - }
> -
> - if (ls->function_name)
> - {
> - if (need_colon)
> - fputc_unfiltered (':', buf);
> - fputs_unfiltered (ls->function_name, buf);
> - need_colon = 1;
> - }
> -
> - if (ls->label_name)
> - {
> - if (need_colon)
> - fputc_unfiltered (':', buf);
> -
> - if (ls->function_name == NULL)
> + if (ls->explicit.function_name == NULL)
> {
> struct symbol *s;
>
> @@ -1805,29 +1760,22 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
> && (VEC_length (symbolp, ls->labels.function_symbols)
> == 1));
> s = VEC_index (symbolp, ls->labels.function_symbols, 0);
> - fputs_unfiltered (SYMBOL_NATURAL_NAME (s), buf);
> - fputc_unfiltered (':', buf);
> + ls->explicit.function_name = xstrdup (SYMBOL_NATURAL_NAME (s));
This is a side-effect not adequately explained in the function comment.
It's not clear from the function comment that LS is modified.
Is the side-effect necessary (in which case let's make the function
comment clearer), or can we avoid it?
> }
>
> - fputs_unfiltered (ls->label_name, buf);
> - need_colon = 1;
> state->canonical->special_display = 1;
> }
>
> - if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
> - {
> - if (need_colon)
> - fputc_unfiltered (':', buf);
> - fprintf_filtered (buf, "%s%d",
> - (ls->line_offset.sign == LINE_OFFSET_NONE ? ""
> - : (ls->line_offset.sign
> - == LINE_OFFSET_PLUS ? "+" : "-")),
> - ls->line_offset.offset);
> - }
> + /* Save everything as an explicit location. */
> + state->canonical->location = new_explicit_location (&ls->explicit);
>
> - EVENT_LOCATION_LINESPEC (state->canonical->location)
> - = ui_file_xstrdup (buf, NULL);
> - ui_file_delete (buf);
> + /* Save a string representation of this linespec. */
> + if (state->is_linespec)
> + state->canonical->location->as_string
> + = explicit_location_to_linespec (&ls->explicit);
> + else
> + state->canonical->location->as_string
> + = explicit_location_to_string (&ls->explicit);
Why do we need to set as_string here again?
Can users of it call event_location_to_string themselves?
There's still the state->is_linespec distinction of course,
feels odd to have it though: something outside of an event_location
is deciding what to store there, feels like an abstraction violation.
> }
>
> /* Given a line offset in LS, construct the relevant SALs. */
> @@ -1867,18 +1815,18 @@ create_sals_line_offset (struct linespec_state *self,
> use_default = 1;
> }
>
> - val.line = ls->line_offset.offset;
> - switch (ls->line_offset.sign)
> + val.line = ls->explicit.line_offset.offset;
> + switch (ls->explicit.line_offset.sign)
> {
> case LINE_OFFSET_PLUS:
> - if (ls->line_offset.offset == 0)
> + if (ls->explicit.line_offset.offset == 0)
> val.line = 5;
> if (use_default)
> val.line = self->default_line + val.line;
> break;
>
> case LINE_OFFSET_MINUS:
> - if (ls->line_offset.offset == 0)
> + if (ls->explicit.line_offset.offset == 0)
> val.line = 15;
> if (use_default)
> val.line = self->default_line - val.line;
> @@ -1970,9 +1918,9 @@ create_sals_line_offset (struct linespec_state *self,
>
> if (values.nelts == 0)
> {
> - if (ls->source_filename)
> + if (ls->explicit.source_filename)
> throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
> - val.line, ls->source_filename);
> + val.line, ls->explicit.source_filename);
> else
> throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
> val.line);
> @@ -2072,13 +2020,13 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
> }
> }
> }
> - else if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
> + else if (ls->explicit.line_offset.sign != LINE_OFFSET_UNKNOWN)
> {
> /* Only an offset was specified. */
> sals = create_sals_line_offset (state, ls);
>
> /* Make sure we have a filename for canonicalization. */
> - if (ls->source_filename == NULL)
> + if (ls->explicit.source_filename == NULL)
> {
> const char *fullname = symtab_to_fullname (state->default_symtab);
>
> @@ -2086,7 +2034,7 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
> form so that displaying SOURCE_FILENAME can follow the current
> FILENAME_DISPLAY_STRING setting. But as it is used only rarely
> it has been kept for code simplicity only in absolute form. */
> - ls->source_filename = xstrdup (fullname);
> + ls->explicit.source_filename = xstrdup (fullname);
> }
> }
> else
> @@ -2103,6 +2051,73 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
> return sals;
> }
>
> +/* Convert the explicit location EXPLICIT into SaLs. */
> +
> +static struct symtabs_and_lines
> +convert_explicit_location_to_sals (struct linespec_state *self,
> + linespec_p result,
> + struct explicit_location *explicit)
How many of these parameters can be const?
> +{
> + VEC (symbolp) *symbols, *labels;
> + VEC (bound_minimal_symbol_d) *minimal_symbols;
> +
> + if (explicit->source_filename != NULL)
> + {
> + volatile struct gdb_exception except;
> +
> + TRY_CATCH (except, RETURN_MASK_ERROR)
> + {
> + result->file_symtabs
> + = symtabs_from_filename (explicit->source_filename);
> + }
> +
> + if (except.reason < 0 || result->file_symtabs == NULL)
> + source_file_not_found_error (explicit->source_filename);
> +
> + result->explicit.source_filename = xstrdup (explicit->source_filename);
> + }
> + else
> + {
> + /* A NULL entry means to use the default symtab. */
> + VEC_safe_push (symtab_ptr, result->file_symtabs, NULL);
> + }
> +
> + if (explicit->function_name != NULL)
> + {
> + find_linespec_symbols (self, result->file_symtabs,
> + explicit->function_name, &symbols,
> + &minimal_symbols);
> +
> + if (symbols == NULL && minimal_symbols == NULL)
> + symbol_not_found_error (explicit->function_name,
> + result->explicit.source_filename);
> +
> + result->explicit.function_name = xstrdup (explicit->function_name);
> + result->function_symbols = symbols;
> + result->minimal_symbols = minimal_symbols;
> + }
> +
> + if (explicit->label_name != NULL)
> + {
> + symbols = NULL;
> + labels = find_label_symbols (self, result->function_symbols,
> + &symbols, explicit->label_name);
> +
> + if (labels == NULL)
> + undefined_label_error (result->explicit.function_name,
> + explicit->label_name);
> +
> + result->explicit.label_name = xstrdup (explicit->label_name);
> + result->labels.label_symbols = labels;
> + result->labels.function_symbols = symbols;
> + }
> +
> + if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
> + result->explicit.line_offset = explicit->line_offset;
> +
> + return convert_linespec_to_sals (self, result);
> +}
> +
> /* Parse a string that specifies a linespec.
> Pass the address of a char * variable; that variable will be
> advanced over the characters actually parsed.
> @@ -2215,13 +2230,13 @@ parse_linespec (linespec_parser *parser, const char **argptr)
> /* User specified a convenience variable or history value. */
> var = copy_token_string (token);
> cleanup = make_cleanup (xfree, var);
> - PARSER_RESULT (parser)->line_offset
> + PARSER_EXPLICIT (parser)->line_offset
> = linespec_parse_variable (PARSER_STATE (parser), var);
> do_cleanups (cleanup);
>
> /* If a line_offset wasn't found (VAR is the name of a user
> variable/function), then skip to normal symbol processing. */
> - if (PARSER_RESULT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
> + if (PARSER_EXPLICIT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
> {
> /* Consume this token. */
> linespec_lexer_consume_token (parser);
> @@ -2257,7 +2272,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
> if (file_exception.reason >= 0)
> {
> /* Symtabs were found for the file. Record the filename. */
> - PARSER_RESULT (parser)->source_filename = user_filename;
> + PARSER_EXPLICIT (parser)->source_filename = user_filename;
>
> /* Get the next token. */
> token = linespec_lexer_consume_token (parser);
> @@ -2294,7 +2309,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
>
> if (PARSER_RESULT (parser)->function_symbols == NULL
> && PARSER_RESULT (parser)->labels.label_symbols == NULL
> - && PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
> + && PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
> && PARSER_RESULT (parser)->minimal_symbols == NULL)
> {
> /* The linespec didn't parse. Re-throw the file exception if
> @@ -2303,8 +2318,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
> throw_exception (file_exception);
>
> /* Otherwise, the symbol is not found. */
> - symbol_not_found_error (PARSER_RESULT (parser)->function_name,
> - PARSER_RESULT (parser)->source_filename);
> + symbol_not_found_error (PARSER_EXPLICIT (parser)->function_name,
> + PARSER_EXPLICIT (parser)->source_filename);
> }
>
> convert_to_sals:
> @@ -2342,6 +2357,7 @@ linespec_state_constructor (struct linespec_state *self,
> self->program_space = current_program_space;
> self->addr_set = htab_create_alloc (10, hash_address_entry, eq_address_entry,
> xfree, xcalloc, xfree);
> + self->is_linespec = 0;
> }
>
> /* Initialize a new linespec parser. */
> @@ -2356,7 +2372,7 @@ linespec_parser_new (linespec_parser *parser,
> memset (parser, 0, sizeof (linespec_parser));
> parser->lexer.current.type = LSTOKEN_CONSUMED;
> memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
> - PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
> + PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
> linespec_state_constructor (PARSER_STATE (parser), flags, language,
> default_symtab, default_line, canonical);
> }
> @@ -2376,10 +2392,9 @@ linespec_parser_delete (void *arg)
> {
> linespec_parser *parser = (linespec_parser *) arg;
>
> - xfree ((char *) PARSER_RESULT (parser)->expression);
> - xfree ((char *) PARSER_RESULT (parser)->source_filename);
> - xfree ((char *) PARSER_RESULT (parser)->label_name);
> - xfree ((char *) PARSER_RESULT (parser)->function_name);
> + xfree (PARSER_EXPLICIT (parser)->source_filename);
> + xfree (PARSER_EXPLICIT (parser)->label_name);
> + xfree (PARSER_EXPLICIT (parser)->function_name);
>
> if (PARSER_RESULT (parser)->file_symtabs != NULL)
> VEC_free (symtab_ptr, PARSER_RESULT (parser)->file_symtabs);
> @@ -2415,6 +2430,7 @@ event_location_to_sals (linespec_parser *parser,
> const char *copy, *orig;
> volatile struct gdb_exception except;
>
> + PARSER_STATE (parser)->is_linespec = 1;
> TRY_CATCH (except, RETURN_MASK_ERROR)
> {
> orig = copy = EVENT_LOCATION_LINESPEC (location);
> @@ -2433,6 +2449,17 @@ event_location_to_sals (linespec_parser *parser,
> EVENT_LOCATION_ADDRESS (location));
> break;
>
> + case EXPLICIT_LOCATION:
> + {
> + struct explicit_location *explicit;
> +
> + explicit = EVENT_LOCATION_EXPLICIT (location);
> + result = convert_explicit_location_to_sals (PARSER_STATE (parser),
> + PARSER_RESULT (parser),
> + explicit);
> + }
> + break;
> +
> case PROBE_LOCATION:
> /* Probes are handled by their own decoders. */
> gdb_assert_not_reached ("attempt to decode probe location");
> @@ -2691,7 +2718,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
> memcpy (saved_arg, *argptr, new_argptr - *argptr);
> saved_arg[new_argptr - *argptr] = '\0';
>
> - ls->function_name = xstrdup (saved_arg);
> + ls->explicit.function_name = xstrdup (saved_arg);
> ls->function_symbols = info.result.symbols;
> ls->minimal_symbols = info.result.minimal_symbols;
> values = convert_linespec_to_sals (self, ls);
> @@ -2701,9 +2728,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
> self->canonical->pre_expanded = 1;
> self->canonical->location = new_linespec_location (NULL);
>
> - if (ls->source_filename)
> + if (ls->explicit.source_filename)
> EVENT_LOCATION_LINESPEC (self->canonical->location)
> - = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
> + = xstrprintf ("%s:%s", ls->explicit.source_filename, saved_arg);
> else
> EVENT_LOCATION_LINESPEC (self->canonical->location)
> = xstrdup (saved_arg);
> @@ -3082,7 +3109,7 @@ symtabs_from_filename (const char *filename)
> throw_error (NOT_FOUND_ERROR,
> _("No symbol table is loaded. "
> "Use the \"file\" command."));
> - throw_error (NOT_FOUND_ERROR, _("No source file named %s."), filename);
> + source_file_not_found_error (filename);
> }
>
> return result;
> diff --git a/gdb/location.c b/gdb/location.c
> index eafa27d..86d4232 100644
> --- a/gdb/location.c
> +++ b/gdb/location.c
> @@ -28,6 +28,15 @@
> #include <ctype.h>
> #include <string.h>
>
> +/* Initialize the given explicit location. */
> +
> +void
> +initialize_explicit_location (struct explicit_location *explicit)
> +{
> + memset (explicit, 0, sizeof (struct explicit_location));
> + explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
> +}
> +
> /* Initialize the given LOCATION. */
>
> void
> @@ -36,6 +45,8 @@ initialize_event_location (struct event_location *location,
> {
> memset (location, 0, sizeof (struct event_location));
> EVENT_LOCATION_TYPE (location) = type;
> + if (type == EXPLICIT_LOCATION)
> + initialize_explicit_location (EVENT_LOCATION_EXPLICIT (location));
> }
>
> /* Create a new linespec location. The return result is malloc'd
> @@ -82,6 +93,49 @@ new_probe_location (const char *probe)
> return location;
> }
>
> +/* Create a new explicit location. If not NULL, EXPLICIT is checked for
> + validity. If invalid, an exception is thrown.
> +
> + The return result is malloc'd and should be freed with
> + delete_event_location. */
> +
> +struct event_location *
> +new_explicit_location (const struct explicit_location *explicit)
> +{
> + struct event_location tmp;
> +
> + initialize_event_location (&tmp, EXPLICIT_LOCATION);
> +
> + if (explicit != NULL)
> + {
> + if (explicit->source_filename != NULL)
> + {
> + /* Error check -- we must have one of the other
> + parameters specified. */
> + if (explicit->function_name == NULL
> + && explicit->label_name == NULL
> + && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
> + error (_("Source filename requires function, label, or "
> + "line offset."));
How about moving this error check into the caller(s)
and have an assert here instead? One could write a utility to
error check an explicit_location, and the callers could call that.
> +
> + EVENT_LOCATION_EXPLICIT (&tmp)->source_filename
> + = explicit->source_filename;
> + }
> +
> + if (explicit->function_name != NULL)
> + EVENT_LOCATION_EXPLICIT (&tmp)->function_name
> + = explicit->function_name;
> +
> + if (explicit->label_name != NULL)
> + EVENT_LOCATION_EXPLICIT (&tmp)->label_name = explicit->label_name;
> +
> + if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
> + EVENT_LOCATION_EXPLICIT (&tmp)->line_offset = explicit->line_offset;
> + }
> +
> + return copy_event_location (&tmp);
> +}
> +
> /* Return a copy of the given SRC location. */
>
> struct event_location *
> @@ -104,6 +158,24 @@ copy_event_location (const struct event_location *src)
> EVENT_LOCATION_ADDRESS (dst) = EVENT_LOCATION_ADDRESS (src);
> break;
>
> + case EXPLICIT_LOCATION:
> + if (EVENT_LOCATION_EXPLICIT (src)->source_filename != NULL)
> + EVENT_LOCATION_EXPLICIT (dst)->source_filename
> + = xstrdup (EVENT_LOCATION_EXPLICIT (src)->source_filename);
> +
> + if (EVENT_LOCATION_EXPLICIT (src)->function_name != NULL)
> + EVENT_LOCATION_EXPLICIT (dst)->function_name
> + = xstrdup (EVENT_LOCATION_EXPLICIT (src)->function_name);
> +
> + if (EVENT_LOCATION_EXPLICIT (src)->label_name != NULL)
> + EVENT_LOCATION_EXPLICIT (dst)->label_name
> + = xstrdup (EVENT_LOCATION_EXPLICIT (src)->label_name);
> +
> + EVENT_LOCATION_EXPLICIT (dst)->line_offset
> + = EVENT_LOCATION_EXPLICIT (src)->line_offset;
> + break;
> +
> +
> case PROBE_LOCATION:
> EVENT_LOCATION_PROBE (dst) = xstrdup (EVENT_LOCATION_PROBE (src));
> break;
> @@ -115,6 +187,87 @@ copy_event_location (const struct event_location *src)
> return dst;
> }
>
> +/* This convenience function returns a malloc'd string which
> + represents the location in EXPLICIT.
> +
> + AS_LINESPEC is non-zero if this string should be a linespec.
> + Otherwise it will be output in explicit form. */
> +
> +static char *
> +explicit_to_string_internal (int as_linespec,
> + const struct explicit_location *explicit)
> +{
> + struct ui_file *buf;
> + char space, *result;
> + int need_space = 0;
> +
> + space = as_linespec ? ':' : ' ';
> + buf = mem_fileopen ();
> +
> + if (explicit->source_filename != NULL)
> + {
> + if (!as_linespec)
> + fputs_unfiltered ("-source ", buf);
> + fputs_unfiltered (explicit->source_filename, buf);
> + need_space = 1;
> + }
> +
> + if (explicit->function_name != NULL)
> + {
> + if (need_space)
> + fputc_unfiltered (space, buf);
> + if (!as_linespec)
> + fputs_unfiltered ("-function ", buf);
> + fputs_unfiltered (explicit->function_name, buf);
> + need_space = 1;
> + }
> +
> + if (explicit->label_name != NULL)
> + {
> + if (need_space)
> + fputc_unfiltered (space, buf);
> + if (!as_linespec)
> + fputs_unfiltered ("-label ", buf);
> + fputs_unfiltered (explicit->label_name, buf);
> + need_space = 1;
> + }
> +
> + if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
> + {
> + if (need_space)
> + fputc_unfiltered (space, buf);
> + if (!as_linespec)
> + fputs_unfiltered ("-line ", buf);
> + fprintf_filtered (buf, "%s%d",
> + (explicit->line_offset.sign == LINE_OFFSET_NONE ? ""
> + : (explicit->line_offset.sign
> + == LINE_OFFSET_PLUS ? "+" : "-")),
> + explicit->line_offset.offset);
> + }
> +
> + result = ui_file_xstrdup (buf, NULL);
> + ui_file_delete (buf);
> + return result;
> +}
> +
> +/* Return a malloc'd explicit string representation of the given
> + explicit location. The location must already be canonicalized/valid. */
> +
> +char *
> +explicit_location_to_string (const struct explicit_location *explicit)
> +{
> + return explicit_to_string_internal (0, explicit);
> +}
> +
> +/* Return a malloc'd linespec string representation of the given
> + explicit location. The location must already be canonicalized/valid. */
> +
> +char *
> +explicit_location_to_linespec (const struct explicit_location *explicit)
> +{
> + return explicit_to_string_internal (1, explicit);
> +}
> +
> /* A cleanup function for struct event_location. */
>
> static void
> @@ -152,6 +305,12 @@ delete_event_location (struct event_location *location)
> /* Nothing to do. */
> break;
>
> + case EXPLICIT_LOCATION:
> + xfree (EVENT_LOCATION_EXPLICIT (location)->source_filename);
> + xfree (EVENT_LOCATION_EXPLICIT (location)->function_name);
> + xfree (EVENT_LOCATION_EXPLICIT (location)->label_name);
> + break;
> +
> case PROBE_LOCATION:
> xfree (EVENT_LOCATION_PROBE (location));
> break;
> @@ -189,6 +348,10 @@ event_location_to_string_const (const struct event_location *location)
> core_addr_to_string (EVENT_LOCATION_ADDRESS (location)));
> break;
>
> + case EXPLICIT_LOCATION:
> + result = explicit_location_to_string (EVENT_LOCATION_EXPLICIT (location));
> + break;
> +
> case PROBE_LOCATION:
> result = xstrdup (EVENT_LOCATION_PROBE (location));
> break;
> @@ -274,6 +437,14 @@ event_location_empty_p (const struct event_location *location)
> case ADDRESS_LOCATION:
> return 0;
>
> + case EXPLICIT_LOCATION:
> + return (EVENT_LOCATION_EXPLICIT (location) == NULL
> + || (EVENT_LOCATION_EXPLICIT (location)->source_filename == NULL
> + && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
> + && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
> + && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
> + == LINE_OFFSET_UNKNOWN)));
> +
> case PROBE_LOCATION:
> return EVENT_LOCATION_PROBE (location) == NULL;
>
> diff --git a/gdb/location.h b/gdb/location.h
> index e6f14d9..709d6f8 100644
> --- a/gdb/location.h
> +++ b/gdb/location.h
> @@ -21,6 +21,32 @@
>
> struct language_defn;
>
> +/* An enumeration of possible signs for a line offset. */
> +
> +enum offset_relative_sign
> +{
> + /* No sign */
> + LINE_OFFSET_NONE,
> +
> + /* A plus sign ("+") */
> + LINE_OFFSET_PLUS,
> +
> + /* A minus sign ("-") */
> + LINE_OFFSET_MINUS,
> +
> + /* A special "sign" for unspecified offset. */
> + LINE_OFFSET_UNKNOWN
> +};
> +
> +/* A line offset in a location. */
> +
> +struct line_offset
> +{
> + /* Line offset and any specified sign. */
> + int offset;
> + enum offset_relative_sign sign;
> +};
> +
> /* An enumeration of the various ways to specify a stop event
> location (used with create_breakpoint). */
>
> @@ -32,10 +58,35 @@ enum event_location_type
> /* An address in the inferior. */
> ADDRESS_LOCATION,
>
> + /* An explicit location. */
> + EXPLICIT_LOCATION,
> +
> /* A probe location. */
> PROBE_LOCATION
> };
>
> +/* An explicit location. This structure is used to bypass the
> + parsing done on linespecs. It still has the same requirements
> + as linespecs, though. For example, source_filename requires
> + at least one other field. */
> +
> +struct explicit_location
> +{
> + /* The source filename. Malloc'd. */
> + char *source_filename;
> +
> + /* The function name. Malloc'd. */
> + char *function_name;
> +
> + /* The name of a label. Malloc'd. */
> + char *label_name;
> +
> + /* A line offset relative to the start of the symbol
> + identified by the above fields or the current symtab
> + if the other fields are NULL. */
> + struct line_offset line_offset;
> +};
> +
> /* An event location used to set a stop event in the inferior.
> This structure is an amalgam of the various ways
> to specify where a stop event should be set. */
> @@ -58,6 +109,10 @@ struct event_location
> /* An address in the inferior. */
> CORE_ADDR address;
> #define EVENT_LOCATION_ADDRESS(S) ((S)->u.address)
> +
> + /* An explicit location. */
> + struct explicit_location explicit;
> +#define EVENT_LOCATION_EXPLICIT(S) (&((S)->u.explicit))
> } u;
>
> /* Cached string representation of this location. This is used to
> @@ -65,6 +120,18 @@ struct event_location
> char *as_string;
> };
>
> +/* Return a malloc'd explicit string representation of the given
> + explicit location. The location must already be canonicalized/valid. */
> +
> +extern char *
> + explicit_location_to_string (const struct explicit_location *explicit);
> +
> +/* Return a malloc'd linespec string representation of the given
> + explicit location. The location must already be canonicalized/valid. */
> +
> +extern char *
> + explicit_location_to_linespec (const struct explicit_location *explicit);
> +
> /* Return a string representation of the LOCATION.
> This function may return NULL for unspecified linespecs,
> e.g, EVENT_LOCATION_LINESPEC and addr_string is NULL.
> @@ -108,6 +175,15 @@ extern struct event_location *
> extern struct event_location *
> new_probe_location (const char *probe);
>
> +/* Create a new explicit location. If not NULL, EXPLICIT is checked for
> + validity. If invalid, an exception is thrown.
> +
> + The return result is malloc'd and should be freed with
> + delete_event_location. */
Copy of function comment in .c file. Delete one.
> +
> +extern struct event_location *
> + new_explicit_location (const struct explicit_location *explicit);
> +
> /* Return a copy of the given SRC location. */
>
> extern struct event_location *
> @@ -118,6 +194,10 @@ extern struct event_location *
> extern void initialize_event_location (struct event_location *location,
> enum event_location_type type);
>
> +/* Initialize the given explicit location. */
> +
> +extern void initialize_explicit_location (struct explicit_location *explicit);
> +
> /* Attempt to convert the input string in *ARGP into an event location.
> ARGP is advanced past any processed input. Returns a event_location
> (malloc'd) if an event location was successfully found in *ARGP,
@@ -3281,6 +3281,7 @@ create_overlay_event_breakpoint (void)
struct breakpoint *b;
struct breakpoint_objfile_data *bp_objfile_data;
CORE_ADDR addr;
+ struct explicit_location explicit;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
@@ -3305,7 +3306,9 @@ create_overlay_event_breakpoint (void)
b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_overlay_event,
&internal_breakpoint_ops);
- b->location = new_linespec_location (func_name);
+ initialize_explicit_location (&explicit);
+ explicit.function_name = ASTRDUP (func_name);
+ b->location = new_explicit_location (&explicit);
if (overlay_debugging == ovly_auto)
{
@@ -3402,6 +3405,7 @@ create_longjmp_master_breakpoint (void)
struct breakpoint *b;
const char *func_name;
CORE_ADDR addr;
+ struct explicit_location explicit;
if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
continue;
@@ -3424,7 +3428,9 @@ create_longjmp_master_breakpoint (void)
addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
&internal_breakpoint_ops);
- b->location = new_linespec_location (func_name);
+ initialize_explicit_location (&explicit);
+ explicit.function_name = ASTRDUP (func_name);
+ b->location = new_explicit_location (&explicit);
b->enable_state = bp_disabled;
}
}
@@ -3455,6 +3461,7 @@ create_std_terminate_master_breakpoint (void)
{
struct breakpoint *b;
struct breakpoint_objfile_data *bp_objfile_data;
+ struct explicit_location explicit;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
@@ -3480,7 +3487,9 @@ create_std_terminate_master_breakpoint (void)
b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
bp_std_terminate_master,
&internal_breakpoint_ops);
- b->location = new_linespec_location (func_name);
+ initialize_explicit_location (&explicit);
+ explicit.function_name = ASTRDUP (func_name);
+ b->location = new_explicit_location (&explicit);
b->enable_state = bp_disabled;
}
}
@@ -3504,6 +3513,7 @@ create_exception_master_breakpoint (void)
struct gdbarch *gdbarch;
struct breakpoint_objfile_data *bp_objfile_data;
CORE_ADDR addr;
+ struct explicit_location explicit;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
@@ -3584,7 +3594,9 @@ create_exception_master_breakpoint (void)
¤t_target);
b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
&internal_breakpoint_ops);
- b->location = new_linespec_location (func_name);
+ initialize_explicit_location (&explicit);
+ explicit.function_name = ASTRDUP (func_name);
+ b->location = new_explicit_location (&explicit);
b->enable_state = bp_disabled;
}
@@ -10010,6 +10022,20 @@ create_breakpoint (struct gdbarch *gdbarch,
init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
b->location = copy_event_location (location);
+ /* If the location has a string representation,
+ save it to the breakpoint's location string cache, since this
+ may be used to save the breakpoint to a file. */
+ if (EVENT_LOCATION_TYPE (b->location) == EXPLICIT_LOCATION)
+ {
+ char *old = event_location_to_string_const (location);
+
+ b->location->as_string
+ = xstrprintf ("%s%s%s", old,
+ (extra_string == NULL ? "" : " "),
+ (extra_string == NULL ? "" : extra_string));
+ xfree (old);
+ }
+
if (parse_arg)
b->cond_string = NULL;
else
@@ -10022,7 +10048,17 @@ create_breakpoint (struct gdbarch *gdbarch,
}
b->cond_string = cond_string;
}
- b->extra_string = NULL;
+
+ /* For explicit locations, EXTRA_STRING may contain breakpoint
+ condition information. Make a private copy of this for the
+ breakpoint. */
+ if (extra_string != NULL && *extra_string != '\0')
+ {
+ b->extra_string = xstrdup (extra_string);
+ make_cleanup (xfree, b->extra_string);
+ }
+ else
+ b->extra_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->condition_not_parsed = 1;
@@ -14212,6 +14248,7 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
struct symbol *sym;
struct static_tracepoint_marker *tpmarker;
struct ui_out *uiout = current_uiout;
+ struct explicit_location explicit;
tpmarker = VEC_index (static_tracepoint_marker_p, markers, 0);
@@ -14253,11 +14290,12 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
b->loc->symtab = sym != NULL ? sal2.symtab : NULL;
delete_event_location (b->location);
- b->location = new_linespec_location (NULL);
- EVENT_LOCATION_LINESPEC (b->location)
- = xstrprintf ("%s:%d",
- symtab_to_filename_for_display (sal2.symtab),
- b->loc->line_number);
+ initialize_explicit_location (&explicit);
+ explicit.source_filename
+ = ASTRDUP (symtab_to_filename_for_display (sal2.symtab));
+ explicit.line_offset.offset = b->loc->line_number;
+ explicit.line_offset.sign = LINE_OFFSET_NONE;
+ b->location = new_explicit_location (&explicit);
/* Might be nice to check if function changed, and warn if
so. */
@@ -66,73 +66,26 @@ typedef struct bound_minimal_symbol bound_minimal_symbol_d;
DEF_VEC_O (bound_minimal_symbol_d);
-/* An enumeration of possible signs for a line offset. */
-enum offset_relative_sign
-{
- /* No sign */
- LINE_OFFSET_NONE,
-
- /* A plus sign ("+") */
- LINE_OFFSET_PLUS,
-
- /* A minus sign ("-") */
- LINE_OFFSET_MINUS,
-
- /* A special "sign" for unspecified offset. */
- LINE_OFFSET_UNKNOWN
-};
-
-/* A line offset in a linespec. */
-
-struct line_offset
-{
- /* Line offset and any specified sign. */
- int offset;
- enum offset_relative_sign sign;
-};
-
/* A linespec. Elements of this structure are filled in by a parser
(either parse_linespec or some other function). The structure is
then converted into SALs by convert_linespec_to_sals. */
struct linespec
{
- /* An expression and the resulting PC. Specifying an expression
- currently precludes the use of other members. */
-
- /* The expression entered by the user. */
- const char *expression;
-
- /* The resulting PC expression derived from evaluating EXPRESSION. */
- CORE_ADDR expr_pc;
-
- /* Any specified file symtabs. */
-
- /* The user-supplied source filename or NULL if none was specified. */
- const char *source_filename;
+ /* An explicit location describing the SaLs. */
+ struct explicit_location explicit;
/* The list of symtabs to search to which to limit the search. May not
- be NULL. If SOURCE_FILENAME is NULL (no user-specified filename),
- FILE_SYMTABS should contain one single NULL member. This will
- cause the code to use the default symtab. */
+ be NULL. If explicit.SOURCE_FILENAME is NULL (no user-specified
+ filename), FILE_SYMTABS should contain one single NULL member. This
+ will cause the code to use the default symtab. */
VEC (symtab_ptr) *file_symtabs;
- /* The name of a function or method and any matching symbols. */
-
- /* The user-specified function name. If no function name was
- supplied, this may be NULL. */
- const char *function_name;
-
/* A list of matching function symbols and minimal symbols. Both lists
may be NULL if no matching symbols were found. */
VEC (symbolp) *function_symbols;
VEC (bound_minimal_symbol_d) *minimal_symbols;
- /* The name of a label and matching symbols. */
-
- /* The user-specified label name. */
- const char *label_name;
-
/* A structure of matching label symbols and the corresponding
function symbol in which the label was found. Both may be NULL
or both must be non-NULL. */
@@ -141,10 +94,6 @@ struct linespec
VEC (symbolp) *label_symbols;
VEC (symbolp) *function_symbols;
} labels;
-
- /* Line offset. It may be LINE_OFFSET_UNKNOWN, meaning that no
- offset was specified. */
- struct line_offset line_offset;
};
typedef struct linespec *linespec_p;
@@ -197,6 +146,9 @@ struct linespec_state
/* This is a set of address_entry objects which is used to prevent
duplicate symbols from being entered into the result. */
htab_t addr_set;
+
+ /* Are we building a linespec? */
+ int is_linespec;
};
/* This is a helper object that is used when collecting symbols into a
@@ -307,6 +259,10 @@ struct ls_parser
};
typedef struct ls_parser linespec_parser;
+/* A convenience macro for accessing the explicit location result of
+ the parser. */
+#define PARSER_EXPLICIT(PPTR) (&PARSER_RESULT ((PPTR))->explicit)
+
/* Prototypes for local functions. */
static void iterate_over_file_blocks (struct symtab *symtab,
@@ -1550,6 +1506,29 @@ unexpected_linespec_error (linespec_parser *parser)
token_type_strings[token.type]);
}
+/* Throw an undefined label error. */
+
+static void ATTRIBUTE_NORETURN
+undefined_label_error (const char *function, const char *label)
+{
+ if (function != NULL)
+ throw_error (NOT_FOUND_ERROR,
+ _("No label \"%s\" defined in function \"%s\"."),
+ label, function);
+ else
+ throw_error (NOT_FOUND_ERROR,
+ _("No label \"%s\" defined in current function."),
+ label);
+}
+
+/* Throw a source file not found error. */
+
+static void ATTRIBUTE_NORETURN
+source_file_not_found_error (const char *name)
+{
+ throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
+}
+
/* Parse and return a line offset in STRING. */
static struct line_offset
@@ -1596,7 +1575,7 @@ linespec_parse_basic (linespec_parser *parser)
/* Record the line offset and get the next token. */
name = copy_token_string (token);
cleanup = make_cleanup (xfree, name);
- PARSER_RESULT (parser)->line_offset = linespec_parse_line_offset (name);
+ PARSER_EXPLICIT (parser)->line_offset = linespec_parse_line_offset (name);
do_cleanups (cleanup);
/* Get the next token. */
@@ -1633,7 +1612,7 @@ linespec_parse_basic (linespec_parser *parser)
{
PARSER_RESULT (parser)->function_symbols = symbols;
PARSER_RESULT (parser)->minimal_symbols = minimal_symbols;
- PARSER_RESULT (parser)->function_name = name;
+ PARSER_EXPLICIT (parser)->function_name = name;
symbols = NULL;
discard_cleanups (cleanup);
}
@@ -1647,7 +1626,7 @@ linespec_parse_basic (linespec_parser *parser)
{
PARSER_RESULT (parser)->labels.label_symbols = labels;
PARSER_RESULT (parser)->labels.function_symbols = symbols;
- PARSER_RESULT (parser)->label_name = name;
+ PARSER_EXPLICIT (parser)->label_name = name;
symbols = NULL;
discard_cleanups (cleanup);
}
@@ -1655,14 +1634,14 @@ linespec_parse_basic (linespec_parser *parser)
&& *LS_TOKEN_STOKEN (token).ptr == '$')
{
/* User specified a convenience variable or history value. */
- PARSER_RESULT (parser)->line_offset
+ PARSER_EXPLICIT (parser)->line_offset
= linespec_parse_variable (PARSER_STATE (parser), name);
- if (PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
+ if (PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN)
{
/* The user-specified variable was not valid. Do not
throw an error here. parse_linespec will do it for us. */
- PARSER_RESULT (parser)->function_name = name;
+ PARSER_EXPLICIT (parser)->function_name = name;
discard_cleanups (cleanup);
return;
}
@@ -1677,7 +1656,7 @@ linespec_parse_basic (linespec_parser *parser)
an error here. parse_linespec will do it for us. */
/* Save a copy of the name we were trying to lookup. */
- PARSER_RESULT (parser)->function_name = name;
+ PARSER_EXPLICIT (parser)->function_name = name;
discard_cleanups (cleanup);
return;
}
@@ -1697,7 +1676,7 @@ linespec_parse_basic (linespec_parser *parser)
get the next token. */
name = copy_token_string (token);
cleanup = make_cleanup (xfree, name);
- PARSER_RESULT (parser)->line_offset
+ PARSER_EXPLICIT (parser)->line_offset
= linespec_parse_line_offset (name);
do_cleanups (cleanup);
@@ -1717,16 +1696,15 @@ linespec_parse_basic (linespec_parser *parser)
{
PARSER_RESULT (parser)->labels.label_symbols = labels;
PARSER_RESULT (parser)->labels.function_symbols = symbols;
- PARSER_RESULT (parser)->label_name = name;
+ PARSER_EXPLICIT (parser)->label_name = name;
symbols = NULL;
discard_cleanups (cleanup);
}
else
{
/* We don't know what it was, but it isn't a label. */
- throw_error (NOT_FOUND_ERROR,
- _("No label \"%s\" defined in function \"%s\"."),
- name, PARSER_RESULT (parser)->function_name);
+ undefined_label_error (PARSER_EXPLICIT (parser)->function_name,
+ name);
}
/* Check for a line offset. */
@@ -1744,7 +1722,7 @@ linespec_parse_basic (linespec_parser *parser)
name = copy_token_string (token);
cleanup = make_cleanup (xfree, name);
- PARSER_RESULT (parser)->line_offset
+ PARSER_EXPLICIT (parser)->line_offset
= linespec_parse_line_offset (name);
do_cleanups (cleanup);
@@ -1761,42 +1739,19 @@ linespec_parse_basic (linespec_parser *parser)
}
/* Canonicalize the linespec contained in LS. The result is saved into
- STATE->canonical. */
+ STATE->canonical. This function handles both linespec and explicit
+ locations. */
static void
canonicalize_linespec (struct linespec_state *state, linespec_p ls)
{
- struct ui_file *buf;
- int need_colon = 0;
-
/* If canonicalization was not requested, no need to do anything. */
if (!state->canonical)
return;
- buf = mem_fileopen ();
-
- state->canonical->location = new_linespec_location (NULL);
-
- if (ls->source_filename)
+ if (ls->explicit.label_name)
{
- fputs_unfiltered (ls->source_filename, buf);
- need_colon = 1;
- }
-
- if (ls->function_name)
- {
- if (need_colon)
- fputc_unfiltered (':', buf);
- fputs_unfiltered (ls->function_name, buf);
- need_colon = 1;
- }
-
- if (ls->label_name)
- {
- if (need_colon)
- fputc_unfiltered (':', buf);
-
- if (ls->function_name == NULL)
+ if (ls->explicit.function_name == NULL)
{
struct symbol *s;
@@ -1805,29 +1760,22 @@ canonicalize_linespec (struct linespec_state *state, linespec_p ls)
&& (VEC_length (symbolp, ls->labels.function_symbols)
== 1));
s = VEC_index (symbolp, ls->labels.function_symbols, 0);
- fputs_unfiltered (SYMBOL_NATURAL_NAME (s), buf);
- fputc_unfiltered (':', buf);
+ ls->explicit.function_name = xstrdup (SYMBOL_NATURAL_NAME (s));
}
- fputs_unfiltered (ls->label_name, buf);
- need_colon = 1;
state->canonical->special_display = 1;
}
- if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
- {
- if (need_colon)
- fputc_unfiltered (':', buf);
- fprintf_filtered (buf, "%s%d",
- (ls->line_offset.sign == LINE_OFFSET_NONE ? ""
- : (ls->line_offset.sign
- == LINE_OFFSET_PLUS ? "+" : "-")),
- ls->line_offset.offset);
- }
+ /* Save everything as an explicit location. */
+ state->canonical->location = new_explicit_location (&ls->explicit);
- EVENT_LOCATION_LINESPEC (state->canonical->location)
- = ui_file_xstrdup (buf, NULL);
- ui_file_delete (buf);
+ /* Save a string representation of this linespec. */
+ if (state->is_linespec)
+ state->canonical->location->as_string
+ = explicit_location_to_linespec (&ls->explicit);
+ else
+ state->canonical->location->as_string
+ = explicit_location_to_string (&ls->explicit);
}
/* Given a line offset in LS, construct the relevant SALs. */
@@ -1867,18 +1815,18 @@ create_sals_line_offset (struct linespec_state *self,
use_default = 1;
}
- val.line = ls->line_offset.offset;
- switch (ls->line_offset.sign)
+ val.line = ls->explicit.line_offset.offset;
+ switch (ls->explicit.line_offset.sign)
{
case LINE_OFFSET_PLUS:
- if (ls->line_offset.offset == 0)
+ if (ls->explicit.line_offset.offset == 0)
val.line = 5;
if (use_default)
val.line = self->default_line + val.line;
break;
case LINE_OFFSET_MINUS:
- if (ls->line_offset.offset == 0)
+ if (ls->explicit.line_offset.offset == 0)
val.line = 15;
if (use_default)
val.line = self->default_line - val.line;
@@ -1970,9 +1918,9 @@ create_sals_line_offset (struct linespec_state *self,
if (values.nelts == 0)
{
- if (ls->source_filename)
+ if (ls->explicit.source_filename)
throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
- val.line, ls->source_filename);
+ val.line, ls->explicit.source_filename);
else
throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
val.line);
@@ -2072,13 +2020,13 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
}
}
}
- else if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ else if (ls->explicit.line_offset.sign != LINE_OFFSET_UNKNOWN)
{
/* Only an offset was specified. */
sals = create_sals_line_offset (state, ls);
/* Make sure we have a filename for canonicalization. */
- if (ls->source_filename == NULL)
+ if (ls->explicit.source_filename == NULL)
{
const char *fullname = symtab_to_fullname (state->default_symtab);
@@ -2086,7 +2034,7 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
form so that displaying SOURCE_FILENAME can follow the current
FILENAME_DISPLAY_STRING setting. But as it is used only rarely
it has been kept for code simplicity only in absolute form. */
- ls->source_filename = xstrdup (fullname);
+ ls->explicit.source_filename = xstrdup (fullname);
}
}
else
@@ -2103,6 +2051,73 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
return sals;
}
+/* Convert the explicit location EXPLICIT into SaLs. */
+
+static struct symtabs_and_lines
+convert_explicit_location_to_sals (struct linespec_state *self,
+ linespec_p result,
+ struct explicit_location *explicit)
+{
+ VEC (symbolp) *symbols, *labels;
+ VEC (bound_minimal_symbol_d) *minimal_symbols;
+
+ if (explicit->source_filename != NULL)
+ {
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ result->file_symtabs
+ = symtabs_from_filename (explicit->source_filename);
+ }
+
+ if (except.reason < 0 || result->file_symtabs == NULL)
+ source_file_not_found_error (explicit->source_filename);
+
+ result->explicit.source_filename = xstrdup (explicit->source_filename);
+ }
+ else
+ {
+ /* A NULL entry means to use the default symtab. */
+ VEC_safe_push (symtab_ptr, result->file_symtabs, NULL);
+ }
+
+ if (explicit->function_name != NULL)
+ {
+ find_linespec_symbols (self, result->file_symtabs,
+ explicit->function_name, &symbols,
+ &minimal_symbols);
+
+ if (symbols == NULL && minimal_symbols == NULL)
+ symbol_not_found_error (explicit->function_name,
+ result->explicit.source_filename);
+
+ result->explicit.function_name = xstrdup (explicit->function_name);
+ result->function_symbols = symbols;
+ result->minimal_symbols = minimal_symbols;
+ }
+
+ if (explicit->label_name != NULL)
+ {
+ symbols = NULL;
+ labels = find_label_symbols (self, result->function_symbols,
+ &symbols, explicit->label_name);
+
+ if (labels == NULL)
+ undefined_label_error (result->explicit.function_name,
+ explicit->label_name);
+
+ result->explicit.label_name = xstrdup (explicit->label_name);
+ result->labels.label_symbols = labels;
+ result->labels.function_symbols = symbols;
+ }
+
+ if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ result->explicit.line_offset = explicit->line_offset;
+
+ return convert_linespec_to_sals (self, result);
+}
+
/* Parse a string that specifies a linespec.
Pass the address of a char * variable; that variable will be
advanced over the characters actually parsed.
@@ -2215,13 +2230,13 @@ parse_linespec (linespec_parser *parser, const char **argptr)
/* User specified a convenience variable or history value. */
var = copy_token_string (token);
cleanup = make_cleanup (xfree, var);
- PARSER_RESULT (parser)->line_offset
+ PARSER_EXPLICIT (parser)->line_offset
= linespec_parse_variable (PARSER_STATE (parser), var);
do_cleanups (cleanup);
/* If a line_offset wasn't found (VAR is the name of a user
variable/function), then skip to normal symbol processing. */
- if (PARSER_RESULT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ if (PARSER_EXPLICIT (parser)->line_offset.sign != LINE_OFFSET_UNKNOWN)
{
/* Consume this token. */
linespec_lexer_consume_token (parser);
@@ -2257,7 +2272,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
if (file_exception.reason >= 0)
{
/* Symtabs were found for the file. Record the filename. */
- PARSER_RESULT (parser)->source_filename = user_filename;
+ PARSER_EXPLICIT (parser)->source_filename = user_filename;
/* Get the next token. */
token = linespec_lexer_consume_token (parser);
@@ -2294,7 +2309,7 @@ parse_linespec (linespec_parser *parser, const char **argptr)
if (PARSER_RESULT (parser)->function_symbols == NULL
&& PARSER_RESULT (parser)->labels.label_symbols == NULL
- && PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
+ && PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
&& PARSER_RESULT (parser)->minimal_symbols == NULL)
{
/* The linespec didn't parse. Re-throw the file exception if
@@ -2303,8 +2318,8 @@ parse_linespec (linespec_parser *parser, const char **argptr)
throw_exception (file_exception);
/* Otherwise, the symbol is not found. */
- symbol_not_found_error (PARSER_RESULT (parser)->function_name,
- PARSER_RESULT (parser)->source_filename);
+ symbol_not_found_error (PARSER_EXPLICIT (parser)->function_name,
+ PARSER_EXPLICIT (parser)->source_filename);
}
convert_to_sals:
@@ -2342,6 +2357,7 @@ linespec_state_constructor (struct linespec_state *self,
self->program_space = current_program_space;
self->addr_set = htab_create_alloc (10, hash_address_entry, eq_address_entry,
xfree, xcalloc, xfree);
+ self->is_linespec = 0;
}
/* Initialize a new linespec parser. */
@@ -2356,7 +2372,7 @@ linespec_parser_new (linespec_parser *parser,
memset (parser, 0, sizeof (linespec_parser));
parser->lexer.current.type = LSTOKEN_CONSUMED;
memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
- PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
+ PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
linespec_state_constructor (PARSER_STATE (parser), flags, language,
default_symtab, default_line, canonical);
}
@@ -2376,10 +2392,9 @@ linespec_parser_delete (void *arg)
{
linespec_parser *parser = (linespec_parser *) arg;
- xfree ((char *) PARSER_RESULT (parser)->expression);
- xfree ((char *) PARSER_RESULT (parser)->source_filename);
- xfree ((char *) PARSER_RESULT (parser)->label_name);
- xfree ((char *) PARSER_RESULT (parser)->function_name);
+ xfree (PARSER_EXPLICIT (parser)->source_filename);
+ xfree (PARSER_EXPLICIT (parser)->label_name);
+ xfree (PARSER_EXPLICIT (parser)->function_name);
if (PARSER_RESULT (parser)->file_symtabs != NULL)
VEC_free (symtab_ptr, PARSER_RESULT (parser)->file_symtabs);
@@ -2415,6 +2430,7 @@ event_location_to_sals (linespec_parser *parser,
const char *copy, *orig;
volatile struct gdb_exception except;
+ PARSER_STATE (parser)->is_linespec = 1;
TRY_CATCH (except, RETURN_MASK_ERROR)
{
orig = copy = EVENT_LOCATION_LINESPEC (location);
@@ -2433,6 +2449,17 @@ event_location_to_sals (linespec_parser *parser,
EVENT_LOCATION_ADDRESS (location));
break;
+ case EXPLICIT_LOCATION:
+ {
+ struct explicit_location *explicit;
+
+ explicit = EVENT_LOCATION_EXPLICIT (location);
+ result = convert_explicit_location_to_sals (PARSER_STATE (parser),
+ PARSER_RESULT (parser),
+ explicit);
+ }
+ break;
+
case PROBE_LOCATION:
/* Probes are handled by their own decoders. */
gdb_assert_not_reached ("attempt to decode probe location");
@@ -2691,7 +2718,7 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
memcpy (saved_arg, *argptr, new_argptr - *argptr);
saved_arg[new_argptr - *argptr] = '\0';
- ls->function_name = xstrdup (saved_arg);
+ ls->explicit.function_name = xstrdup (saved_arg);
ls->function_symbols = info.result.symbols;
ls->minimal_symbols = info.result.minimal_symbols;
values = convert_linespec_to_sals (self, ls);
@@ -2701,9 +2728,9 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char **argptr)
self->canonical->pre_expanded = 1;
self->canonical->location = new_linespec_location (NULL);
- if (ls->source_filename)
+ if (ls->explicit.source_filename)
EVENT_LOCATION_LINESPEC (self->canonical->location)
- = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
+ = xstrprintf ("%s:%s", ls->explicit.source_filename, saved_arg);
else
EVENT_LOCATION_LINESPEC (self->canonical->location)
= xstrdup (saved_arg);
@@ -3082,7 +3109,7 @@ symtabs_from_filename (const char *filename)
throw_error (NOT_FOUND_ERROR,
_("No symbol table is loaded. "
"Use the \"file\" command."));
- throw_error (NOT_FOUND_ERROR, _("No source file named %s."), filename);
+ source_file_not_found_error (filename);
}
return result;
@@ -28,6 +28,15 @@
#include <ctype.h>
#include <string.h>
+/* Initialize the given explicit location. */
+
+void
+initialize_explicit_location (struct explicit_location *explicit)
+{
+ memset (explicit, 0, sizeof (struct explicit_location));
+ explicit->line_offset.sign = LINE_OFFSET_UNKNOWN;
+}
+
/* Initialize the given LOCATION. */
void
@@ -36,6 +45,8 @@ initialize_event_location (struct event_location *location,
{
memset (location, 0, sizeof (struct event_location));
EVENT_LOCATION_TYPE (location) = type;
+ if (type == EXPLICIT_LOCATION)
+ initialize_explicit_location (EVENT_LOCATION_EXPLICIT (location));
}
/* Create a new linespec location. The return result is malloc'd
@@ -82,6 +93,49 @@ new_probe_location (const char *probe)
return location;
}
+/* Create a new explicit location. If not NULL, EXPLICIT is checked for
+ validity. If invalid, an exception is thrown.
+
+ The return result is malloc'd and should be freed with
+ delete_event_location. */
+
+struct event_location *
+new_explicit_location (const struct explicit_location *explicit)
+{
+ struct event_location tmp;
+
+ initialize_event_location (&tmp, EXPLICIT_LOCATION);
+
+ if (explicit != NULL)
+ {
+ if (explicit->source_filename != NULL)
+ {
+ /* Error check -- we must have one of the other
+ parameters specified. */
+ if (explicit->function_name == NULL
+ && explicit->label_name == NULL
+ && explicit->line_offset.sign == LINE_OFFSET_UNKNOWN)
+ error (_("Source filename requires function, label, or "
+ "line offset."));
+
+ EVENT_LOCATION_EXPLICIT (&tmp)->source_filename
+ = explicit->source_filename;
+ }
+
+ if (explicit->function_name != NULL)
+ EVENT_LOCATION_EXPLICIT (&tmp)->function_name
+ = explicit->function_name;
+
+ if (explicit->label_name != NULL)
+ EVENT_LOCATION_EXPLICIT (&tmp)->label_name = explicit->label_name;
+
+ if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ EVENT_LOCATION_EXPLICIT (&tmp)->line_offset = explicit->line_offset;
+ }
+
+ return copy_event_location (&tmp);
+}
+
/* Return a copy of the given SRC location. */
struct event_location *
@@ -104,6 +158,24 @@ copy_event_location (const struct event_location *src)
EVENT_LOCATION_ADDRESS (dst) = EVENT_LOCATION_ADDRESS (src);
break;
+ case EXPLICIT_LOCATION:
+ if (EVENT_LOCATION_EXPLICIT (src)->source_filename != NULL)
+ EVENT_LOCATION_EXPLICIT (dst)->source_filename
+ = xstrdup (EVENT_LOCATION_EXPLICIT (src)->source_filename);
+
+ if (EVENT_LOCATION_EXPLICIT (src)->function_name != NULL)
+ EVENT_LOCATION_EXPLICIT (dst)->function_name
+ = xstrdup (EVENT_LOCATION_EXPLICIT (src)->function_name);
+
+ if (EVENT_LOCATION_EXPLICIT (src)->label_name != NULL)
+ EVENT_LOCATION_EXPLICIT (dst)->label_name
+ = xstrdup (EVENT_LOCATION_EXPLICIT (src)->label_name);
+
+ EVENT_LOCATION_EXPLICIT (dst)->line_offset
+ = EVENT_LOCATION_EXPLICIT (src)->line_offset;
+ break;
+
+
case PROBE_LOCATION:
EVENT_LOCATION_PROBE (dst) = xstrdup (EVENT_LOCATION_PROBE (src));
break;
@@ -115,6 +187,87 @@ copy_event_location (const struct event_location *src)
return dst;
}
+/* This convenience function returns a malloc'd string which
+ represents the location in EXPLICIT.
+
+ AS_LINESPEC is non-zero if this string should be a linespec.
+ Otherwise it will be output in explicit form. */
+
+static char *
+explicit_to_string_internal (int as_linespec,
+ const struct explicit_location *explicit)
+{
+ struct ui_file *buf;
+ char space, *result;
+ int need_space = 0;
+
+ space = as_linespec ? ':' : ' ';
+ buf = mem_fileopen ();
+
+ if (explicit->source_filename != NULL)
+ {
+ if (!as_linespec)
+ fputs_unfiltered ("-source ", buf);
+ fputs_unfiltered (explicit->source_filename, buf);
+ need_space = 1;
+ }
+
+ if (explicit->function_name != NULL)
+ {
+ if (need_space)
+ fputc_unfiltered (space, buf);
+ if (!as_linespec)
+ fputs_unfiltered ("-function ", buf);
+ fputs_unfiltered (explicit->function_name, buf);
+ need_space = 1;
+ }
+
+ if (explicit->label_name != NULL)
+ {
+ if (need_space)
+ fputc_unfiltered (space, buf);
+ if (!as_linespec)
+ fputs_unfiltered ("-label ", buf);
+ fputs_unfiltered (explicit->label_name, buf);
+ need_space = 1;
+ }
+
+ if (explicit->line_offset.sign != LINE_OFFSET_UNKNOWN)
+ {
+ if (need_space)
+ fputc_unfiltered (space, buf);
+ if (!as_linespec)
+ fputs_unfiltered ("-line ", buf);
+ fprintf_filtered (buf, "%s%d",
+ (explicit->line_offset.sign == LINE_OFFSET_NONE ? ""
+ : (explicit->line_offset.sign
+ == LINE_OFFSET_PLUS ? "+" : "-")),
+ explicit->line_offset.offset);
+ }
+
+ result = ui_file_xstrdup (buf, NULL);
+ ui_file_delete (buf);
+ return result;
+}
+
+/* Return a malloc'd explicit string representation of the given
+ explicit location. The location must already be canonicalized/valid. */
+
+char *
+explicit_location_to_string (const struct explicit_location *explicit)
+{
+ return explicit_to_string_internal (0, explicit);
+}
+
+/* Return a malloc'd linespec string representation of the given
+ explicit location. The location must already be canonicalized/valid. */
+
+char *
+explicit_location_to_linespec (const struct explicit_location *explicit)
+{
+ return explicit_to_string_internal (1, explicit);
+}
+
/* A cleanup function for struct event_location. */
static void
@@ -152,6 +305,12 @@ delete_event_location (struct event_location *location)
/* Nothing to do. */
break;
+ case EXPLICIT_LOCATION:
+ xfree (EVENT_LOCATION_EXPLICIT (location)->source_filename);
+ xfree (EVENT_LOCATION_EXPLICIT (location)->function_name);
+ xfree (EVENT_LOCATION_EXPLICIT (location)->label_name);
+ break;
+
case PROBE_LOCATION:
xfree (EVENT_LOCATION_PROBE (location));
break;
@@ -189,6 +348,10 @@ event_location_to_string_const (const struct event_location *location)
core_addr_to_string (EVENT_LOCATION_ADDRESS (location)));
break;
+ case EXPLICIT_LOCATION:
+ result = explicit_location_to_string (EVENT_LOCATION_EXPLICIT (location));
+ break;
+
case PROBE_LOCATION:
result = xstrdup (EVENT_LOCATION_PROBE (location));
break;
@@ -274,6 +437,14 @@ event_location_empty_p (const struct event_location *location)
case ADDRESS_LOCATION:
return 0;
+ case EXPLICIT_LOCATION:
+ return (EVENT_LOCATION_EXPLICIT (location) == NULL
+ || (EVENT_LOCATION_EXPLICIT (location)->source_filename == NULL
+ && EVENT_LOCATION_EXPLICIT (location)->function_name == NULL
+ && EVENT_LOCATION_EXPLICIT (location)->label_name == NULL
+ && (EVENT_LOCATION_EXPLICIT (location)->line_offset.sign
+ == LINE_OFFSET_UNKNOWN)));
+
case PROBE_LOCATION:
return EVENT_LOCATION_PROBE (location) == NULL;
@@ -21,6 +21,32 @@
struct language_defn;
+/* An enumeration of possible signs for a line offset. */
+
+enum offset_relative_sign
+{
+ /* No sign */
+ LINE_OFFSET_NONE,
+
+ /* A plus sign ("+") */
+ LINE_OFFSET_PLUS,
+
+ /* A minus sign ("-") */
+ LINE_OFFSET_MINUS,
+
+ /* A special "sign" for unspecified offset. */
+ LINE_OFFSET_UNKNOWN
+};
+
+/* A line offset in a location. */
+
+struct line_offset
+{
+ /* Line offset and any specified sign. */
+ int offset;
+ enum offset_relative_sign sign;
+};
+
/* An enumeration of the various ways to specify a stop event
location (used with create_breakpoint). */
@@ -32,10 +58,35 @@ enum event_location_type
/* An address in the inferior. */
ADDRESS_LOCATION,
+ /* An explicit location. */
+ EXPLICIT_LOCATION,
+
/* A probe location. */
PROBE_LOCATION
};
+/* An explicit location. This structure is used to bypass the
+ parsing done on linespecs. It still has the same requirements
+ as linespecs, though. For example, source_filename requires
+ at least one other field. */
+
+struct explicit_location
+{
+ /* The source filename. Malloc'd. */
+ char *source_filename;
+
+ /* The function name. Malloc'd. */
+ char *function_name;
+
+ /* The name of a label. Malloc'd. */
+ char *label_name;
+
+ /* A line offset relative to the start of the symbol
+ identified by the above fields or the current symtab
+ if the other fields are NULL. */
+ struct line_offset line_offset;
+};
+
/* An event location used to set a stop event in the inferior.
This structure is an amalgam of the various ways
to specify where a stop event should be set. */
@@ -58,6 +109,10 @@ struct event_location
/* An address in the inferior. */
CORE_ADDR address;
#define EVENT_LOCATION_ADDRESS(S) ((S)->u.address)
+
+ /* An explicit location. */
+ struct explicit_location explicit;
+#define EVENT_LOCATION_EXPLICIT(S) (&((S)->u.explicit))
} u;
/* Cached string representation of this location. This is used to
@@ -65,6 +120,18 @@ struct event_location
char *as_string;
};
+/* Return a malloc'd explicit string representation of the given
+ explicit location. The location must already be canonicalized/valid. */
+
+extern char *
+ explicit_location_to_string (const struct explicit_location *explicit);
+
+/* Return a malloc'd linespec string representation of the given
+ explicit location. The location must already be canonicalized/valid. */
+
+extern char *
+ explicit_location_to_linespec (const struct explicit_location *explicit);
+
/* Return a string representation of the LOCATION.
This function may return NULL for unspecified linespecs,
e.g, EVENT_LOCATION_LINESPEC and addr_string is NULL.
@@ -108,6 +175,15 @@ extern struct event_location *
extern struct event_location *
new_probe_location (const char *probe);
+/* Create a new explicit location. If not NULL, EXPLICIT is checked for
+ validity. If invalid, an exception is thrown.
+
+ The return result is malloc'd and should be freed with
+ delete_event_location. */
+
+extern struct event_location *
+ new_explicit_location (const struct explicit_location *explicit);
+
/* Return a copy of the given SRC location. */
extern struct event_location *
@@ -118,6 +194,10 @@ extern struct event_location *
extern void initialize_event_location (struct event_location *location,
enum event_location_type type);
+/* Initialize the given explicit location. */
+
+extern void initialize_explicit_location (struct explicit_location *explicit);
+
/* Attempt to convert the input string in *ARGP into an event location.
ARGP is advanced past any processed input. Returns a event_location
(malloc'd) if an event location was successfully found in *ARGP,