| Index: gdb/linespec.c
|
| diff --git a/gdb/linespec.c b/gdb/linespec.c
|
| index 54e699fc1243220c1fabf8a754ba4d64f878ffe3..683299968a52c8a112b5cac634a50170b377f02c 100644
|
| --- a/gdb/linespec.c
|
| +++ b/gdb/linespec.c
|
| @@ -43,6 +43,7 @@
|
| #include "cli/cli-utils.h"
|
| #include "filenames.h"
|
| #include "ada-lang.h"
|
| +#include "stack.h"
|
|
|
| typedef struct symtab *symtab_p;
|
| DEF_VEC_P (symtab_p);
|
| @@ -63,12 +64,108 @@ struct address_entry
|
| CORE_ADDR addr;
|
| };
|
|
|
| +/* A helper struct which just holds a minimal symbol and the object
|
| + file from which it came. */
|
| +
|
| +typedef struct minsym_and_objfile
|
| +{
|
| + struct minimal_symbol *minsym;
|
| + struct objfile *objfile;
|
| +} minsym_and_objfile_d;
|
| +
|
| +DEF_VEC_O (minsym_and_objfile_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. */
|
| + 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. */
|
| + char *source_filename;
|
| +
|
| + /* 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. */
|
| + VEC (symtab_p) *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. */
|
| + 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 (minsym_and_objfile_d) *minimal_symbols;
|
| +
|
| + /* The name of a label and matching symbols. */
|
| +
|
| + /* The user-specified label name. */
|
| + 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. */
|
| + struct
|
| + {
|
| + 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;
|
| +
|
| /* An instance of this is used to keep all state while linespec
|
| operates. This instance is passed around as a 'this' pointer to
|
| the various implementation methods. */
|
|
|
| struct linespec_state
|
| {
|
| + /* The language in use during linespec processing. */
|
| + const struct language_defn *language;
|
| +
|
| /* The program space as seen when the module was entered. */
|
| struct program_space *program_space;
|
|
|
| @@ -78,19 +175,6 @@ struct linespec_state
|
| /* The default line to use. */
|
| int default_line;
|
|
|
| - /* If the linespec started with "FILE:", this holds all the matching
|
| - symtabs. Otherwise, it will hold a single NULL entry, meaning
|
| - that the default symtab should be used. */
|
| - VEC (symtab_p) *file_symtabs;
|
| -
|
| - /* If the linespec started with "FILE:", this holds an xmalloc'd
|
| - copy of "FILE". */
|
| - char *user_filename;
|
| -
|
| - /* If the linespec is "FUNCTION:LABEL", this holds an xmalloc'd copy
|
| - of "FUNCTION". */
|
| - char *user_function;
|
| -
|
| /* The 'funfirstline' value that was passed in to decode_line_1 or
|
| decode_line_full. */
|
| int funfirstline;
|
| @@ -117,67 +201,133 @@ struct collect_info
|
| /* The linespec object in use. */
|
| struct linespec_state *state;
|
|
|
| + /* A list of symtabs to which to restrict matches. */
|
| + VEC (symtab_p) *file_symtabs;
|
| +
|
| /* The result being accumulated. */
|
| - struct symtabs_and_lines result;
|
| + struct
|
| + {
|
| + VEC (symbolp) *symbols;
|
| + VEC (minsym_and_objfile_d) *minimal_symbols;
|
| + } result;
|
| };
|
|
|
| -/* Prototypes for local functions. */
|
| +/* Token types */
|
|
|
| -static void initialize_defaults (struct symtab **default_symtab,
|
| - int *default_line);
|
| +enum ls_token_type
|
| +{
|
| + /* A keyword */
|
| + LSTOKEN_KEYWORD = 0,
|
|
|
| -static struct symtabs_and_lines decode_indirect (struct linespec_state *self,
|
| - char **argptr);
|
| + /* A colon "separator" */
|
| + LSTOKEN_COLON,
|
|
|
| -static char *locate_first_half (char **argptr, int *is_quote_enclosed);
|
| + /* A string */
|
| + LSTOKEN_STRING,
|
|
|
| -static struct symtabs_and_lines decode_objc (struct linespec_state *self,
|
| - char **argptr);
|
| + /* A number */
|
| + LSTOKEN_NUMBER,
|
| +
|
| + /* A comma */
|
| + LSTOKEN_COMMA,
|
| +
|
| + /* EOI (end of input) */
|
| + LSTOKEN_EOI,
|
| +
|
| + /* Consumed token */
|
| + LSTOKEN_CONSUMED
|
| +};
|
| +typedef enum ls_token_type linespec_token_type;
|
| +
|
| +/* List of keywords */
|
| +
|
| +static const char * const linespec_keywords[] = { "if", "thread", "task" };
|
| +
|
| +/* A token of the linespec lexer */
|
| +
|
| +struct ls_token
|
| +{
|
| + /* The type of the token */
|
| + linespec_token_type type;
|
| +
|
| + /* Data for the token */
|
| + union
|
| + {
|
| + /* A string, given as a stoken */
|
| + struct stoken string;
|
| +
|
| + /* A keyword */
|
| + const char *keyword;
|
| + } data;
|
| +};
|
| +typedef struct ls_token linespec_token;
|
| +
|
| +#define LS_TOKEN_STOKEN(TOK) (TOK).data.string
|
| +#define LS_TOKEN_KEYWORD(TOK) (TOK).data.keyword
|
| +
|
| +/* An instance of the linespec parser. */
|
| +
|
| +struct ls_parser
|
| +{
|
| + /* Lexer internal data */
|
| + struct
|
| + {
|
| + /* Save head of input stream. */
|
| + char *saved_arg;
|
|
|
| -static struct symtabs_and_lines decode_compound (struct linespec_state *self,
|
| - char **argptr,
|
| - char *saved_arg,
|
| - char *p);
|
| + /* Head of the input stream. */
|
| + char **stream;
|
| +#define PARSER_STREAM(P) (*(P)->lexer.stream)
|
|
|
| -static VEC (symbolp) *lookup_prefix_sym (char **argptr, char *p,
|
| - VEC (symtab_p) *,
|
| - char **);
|
| + /* The current token. */
|
| + linespec_token current;
|
| + } lexer;
|
|
|
| -static struct symtabs_and_lines find_method (struct linespec_state *self,
|
| - char *saved_arg,
|
| - char *copy,
|
| - const char *class_name,
|
| - VEC (symbolp) *sym_classes);
|
| + /* Is the entire linespec quote-enclosed? */
|
| + int is_quote_enclosed;
|
| +
|
| + /* Is a keyword syntactically valid at this point?
|
| + In, e.g., "break thread thread 1", the leading "keyword" must not
|
| + be interpreted as such. */
|
| + int keyword_ok;
|
| +
|
| + /* The state of the parse. */
|
| + struct linespec_state state;
|
| +#define PARSER_STATE(PPTR) (&(PPTR)->state)
|
|
|
| -static void cplusplus_error (const char *name, const char *fmt, ...)
|
| - ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
|
| + /* The result of the parse. */
|
| + struct linespec result;
|
| +#define PARSER_RESULT(PPTR) (&(PPTR)->result)
|
| +};
|
| +typedef struct ls_parser linespec_parser;
|
|
|
| -static char *find_toplevel_char (char *s, char c);
|
| +/* Prototypes for local functions. */
|
|
|
| -static int is_objc_method_format (const char *s);
|
| +static void initialize_defaults (struct symtab **default_symtab,
|
| + int *default_line);
|
|
|
| -static VEC (symtab_p) *symtabs_from_filename (char **argptr,
|
| - char *p, int is_quote_enclosed,
|
| - char **user_filename);
|
| +static CORE_ADDR linespec_expression_to_pc (char **exp_ptr);
|
|
|
| -static VEC (symbolp) *find_function_symbols (char **argptr, char *p,
|
| - int is_quote_enclosed,
|
| - char **user_function);
|
| +static struct symtabs_and_lines decode_objc (struct linespec_state *self,
|
| + linespec_p ls,
|
| + char **argptr);
|
|
|
| -static struct symtabs_and_lines decode_all_digits (struct linespec_state *self,
|
| - char **argptr,
|
| - char *q);
|
| +static VEC (symtab_p) *symtabs_from_filename (const char *);
|
|
|
| -static struct symtabs_and_lines decode_dollar (struct linespec_state *self,
|
| - char *copy);
|
| +static VEC (symbolp) *find_label_symbols (struct linespec_state *self,
|
| + VEC (symbolp) *function_symbols,
|
| + VEC (symbolp) **label_funcs_ret,
|
| + const char *name);
|
|
|
| -static int decode_label (struct linespec_state *self,
|
| - VEC (symbolp) *function_symbols,
|
| - char *copy,
|
| - struct symtabs_and_lines *result);
|
| +void find_linespec_symbols (struct linespec_state *self,
|
| + VEC (symtab_p) *file_symtabs,
|
| + const char *name,
|
| + VEC (symbolp) **symbols,
|
| + VEC (minsym_and_objfile_d) **minsyms);
|
|
|
| -static struct symtabs_and_lines decode_variable (struct linespec_state *self,
|
| - char *copy);
|
| +static struct line_offset
|
| + linespec_parse_variable (struct linespec_state *self,
|
| + const char *variable);
|
|
|
| static int symbol_to_sal (struct symtab_and_line *result,
|
| int funfirstline, struct symbol *sym);
|
| @@ -190,238 +340,740 @@ static void add_all_symbol_names_from_pspace (struct collect_info *info,
|
| struct program_space *pspace,
|
| VEC (const_char_ptr) *names);
|
|
|
| -/* Helper functions. */
|
| +static VEC (symtab_p) *collect_symtabs_from_filename (const char *file);
|
|
|
| -/* Add SAL to SALS. */
|
| +static void decode_digits_ordinary (struct linespec_state *self,
|
| + linespec_p ls,
|
| + int line,
|
| + struct symtabs_and_lines *sals,
|
| + struct linetable_entry **best_entry);
|
|
|
| -static void
|
| -add_sal_to_sals_basic (struct symtabs_and_lines *sals,
|
| - struct symtab_and_line *sal)
|
| -{
|
| - ++sals->nelts;
|
| - sals->sals = xrealloc (sals->sals, sals->nelts * sizeof (sals->sals[0]));
|
| - sals->sals[sals->nelts - 1] = *sal;
|
| -}
|
| +static void decode_digits_list_mode (struct linespec_state *self,
|
| + linespec_p ls,
|
| + struct symtabs_and_lines *values,
|
| + struct symtab_and_line val);
|
|
|
| -/* Add SAL to SALS, and also update SELF->CANONICAL_NAMES to reflect
|
| - the new sal, if needed. If not NULL, SYMNAME is the name of the
|
| - symbol to use when constructing the new canonical name. */
|
| +static void minsym_found (struct linespec_state *self, struct objfile *objfile,
|
| + struct minimal_symbol *msymbol,
|
| + struct symtabs_and_lines *result);
|
|
|
| -static void
|
| -add_sal_to_sals (struct linespec_state *self,
|
| - struct symtabs_and_lines *sals,
|
| - struct symtab_and_line *sal,
|
| - const char *symname)
|
| +static int compare_symbols (const void *a, const void *b);
|
| +
|
| +static int compare_msymbols (const void *a, const void *b);
|
| +
|
| +static const char *find_toplevel_char (const char *s, char c);
|
| +
|
| +/* Permitted quote characters for the parser. This is different from the
|
| + completer's quote characters to allow backward compatibility with the
|
| + previous parser. */
|
| +static const char *const linespec_quote_characters = "\"\'";
|
| +
|
| +/* Lexer functions. */
|
| +
|
| +/* Lex a number from the input in PARSER. This only supports
|
| + decimal numbers.
|
| +
|
| + Return true if input is decimal numbers. Return false if not. */
|
| +
|
| +static int
|
| +linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
|
| {
|
| - add_sal_to_sals_basic (sals, sal);
|
| + tokenp->type = LSTOKEN_NUMBER;
|
| + LS_TOKEN_STOKEN (*tokenp).length = 0;
|
| + LS_TOKEN_STOKEN (*tokenp).ptr = PARSER_STREAM (parser);
|
|
|
| - if (self->canonical)
|
| + /* Keep any sign at the start of the stream. */
|
| + if (*PARSER_STREAM (parser) == '+' || *PARSER_STREAM (parser) == '-')
|
| {
|
| - char *canonical_name = NULL;
|
| -
|
| - self->canonical_names = xrealloc (self->canonical_names,
|
| - sals->nelts * sizeof (char *));
|
| - if (sal->symtab && sal->symtab->filename)
|
| - {
|
| - char *filename = sal->symtab->filename;
|
| + ++LS_TOKEN_STOKEN (*tokenp).length;
|
| + ++(PARSER_STREAM (parser));
|
| + }
|
|
|
| - /* Note that the filter doesn't have to be a valid linespec
|
| - input. We only apply the ":LINE" treatment to Ada for
|
| - the time being. */
|
| - if (symname != NULL && sal->line != 0
|
| - && current_language->la_language == language_ada)
|
| - canonical_name = xstrprintf ("%s:%s:%d", filename, symname,
|
| - sal->line);
|
| - else if (symname != NULL)
|
| - canonical_name = xstrprintf ("%s:%s", filename, symname);
|
| - else
|
| - canonical_name = xstrprintf ("%s:%d", filename, sal->line);
|
| - }
|
| + while (isdigit (*PARSER_STREAM (parser)))
|
| + {
|
| + ++LS_TOKEN_STOKEN (*tokenp).length;
|
| + ++(PARSER_STREAM (parser));
|
| + }
|
|
|
| - self->canonical_names[sals->nelts - 1] = canonical_name;
|
| + /* If the next character in the input buffer is not a space, comma,
|
| + quote, or colon, the input does not represent a number. */
|
| + if (*PARSER_STREAM (parser) != '\0'
|
| + && !isspace (*PARSER_STREAM (parser)) && *PARSER_STREAM (parser) != ','
|
| + && *PARSER_STREAM (parser) != ':'
|
| + && !strchr (linespec_quote_characters, *PARSER_STREAM (parser)))
|
| + {
|
| + PARSER_STREAM (parser) = LS_TOKEN_STOKEN (*tokenp).ptr;
|
| + return 0;
|
| }
|
| +
|
| + return 1;
|
| }
|
|
|
| -/* A hash function for address_entry. */
|
| +/* Does P represent one of the keywords? If so, return
|
| + the keyword. If not, return NULL. */
|
|
|
| -static hashval_t
|
| -hash_address_entry (const void *p)
|
| +static const char *
|
| +linespec_lexer_lex_keyword (const char *p)
|
| {
|
| - const struct address_entry *aep = p;
|
| - hashval_t hash;
|
| + int i;
|
|
|
| - hash = iterative_hash_object (aep->pspace, 0);
|
| - return iterative_hash_object (aep->addr, hash);
|
| + if (p != NULL)
|
| + {
|
| + for (i = 0; i < ARRAY_SIZE (linespec_keywords); ++i)
|
| + {
|
| + int len = strlen (linespec_keywords[i]);
|
| +
|
| + /* If P begins with one of the keywords and the next
|
| + character is not a valid identifier character,
|
| + we have found a keyword. */
|
| + if (strncmp (p, linespec_keywords[i], len) == 0
|
| + && !(isalnum (p[len]) || p[len] == '_'))
|
| + return linespec_keywords[i];
|
| + }
|
| + }
|
| +
|
| + return NULL;
|
| }
|
|
|
| -/* An equality function for address_entry. */
|
| +/* Does STRING represent an Ada operator? If so, return the length
|
| + of the decoded operator name. If not, return 0. */
|
|
|
| static int
|
| -eq_address_entry (const void *a, const void *b)
|
| +is_ada_operator (const char *string)
|
| {
|
| - const struct address_entry *aea = a;
|
| - const struct address_entry *aeb = b;
|
| + const struct ada_opname_map *mapping;
|
|
|
| - return aea->pspace == aeb->pspace && aea->addr == aeb->addr;
|
| + for (mapping = ada_opname_table;
|
| + mapping->encoded != NULL
|
| + && strncmp (mapping->decoded, string,
|
| + strlen (mapping->decoded)) != 0; ++mapping)
|
| + ;
|
| +
|
| + return mapping->decoded == NULL ? 0 : strlen (mapping->decoded);
|
| }
|
|
|
| -/* Check whether the address, represented by PSPACE and ADDR, is
|
| - already in the set. If so, return 0. Otherwise, add it and return
|
| - 1. */
|
| +/* Find QUOTE_CHAR in STRING, accounting for the ':' terminal. Return
|
| + the location of QUOTE_CHAR, or NULL if not found. */
|
|
|
| -static int
|
| -maybe_add_address (htab_t set, struct program_space *pspace, CORE_ADDR addr)
|
| +static const char *
|
| +skip_quote_char (const char *string, char quote_char)
|
| {
|
| - struct address_entry e, *p;
|
| - void **slot;
|
| -
|
| - e.pspace = pspace;
|
| - e.addr = addr;
|
| - slot = htab_find_slot (set, &e, INSERT);
|
| - if (*slot)
|
| - return 0;
|
| + const char *p, *last;
|
|
|
| - p = XNEW (struct address_entry);
|
| - memcpy (p, &e, sizeof (struct address_entry));
|
| - *slot = p;
|
| + p = last = find_toplevel_char (string, quote_char);
|
| + while (p && *p != '\0' && *p != ':')
|
| + {
|
| + p = find_toplevel_char (p, quote_char);
|
| + if (p != NULL)
|
| + last = p++;
|
| + }
|
|
|
| - return 1;
|
| + return last;
|
| }
|
|
|
| -/* Issue a helpful hint on using the command completion feature on
|
| - single quoted demangled C++ symbols as part of the completion
|
| - error. */
|
| +/* Make a writable copy of the string given in TOKEN, trimming
|
| + any trailing whitespace. */
|
|
|
| -static void
|
| -cplusplus_error (const char *name, const char *fmt, ...)
|
| +static char *
|
| +copy_token_string (linespec_token token)
|
| {
|
| - struct ui_file *tmp_stream;
|
| - char *message;
|
| + char *str, *s;
|
|
|
| - tmp_stream = mem_fileopen ();
|
| - make_cleanup_ui_file_delete (tmp_stream);
|
| + if (token.type == LSTOKEN_KEYWORD)
|
| + return xstrdup (LS_TOKEN_KEYWORD (token));
|
|
|
| - {
|
| - va_list args;
|
| -
|
| - va_start (args, fmt);
|
| - vfprintf_unfiltered (tmp_stream, fmt, args);
|
| - va_end (args);
|
| - }
|
| -
|
| - while (*name == '\'')
|
| - name++;
|
| - fprintf_unfiltered (tmp_stream,
|
| - ("Hint: try '%s<TAB> or '%s<ESC-?>\n"
|
| - "(Note leading single quote.)"),
|
| - name, name);
|
| + str = savestring (LS_TOKEN_STOKEN (token).ptr,
|
| + LS_TOKEN_STOKEN (token).length);
|
| + s = remove_trailing_whitespace (str, str + LS_TOKEN_STOKEN (token).length);
|
| + *s = '\0';
|
|
|
| - message = ui_file_xstrdup (tmp_stream, NULL);
|
| - make_cleanup (xfree, message);
|
| - throw_error (NOT_FOUND_ERROR, "%s", message);
|
| + return str;
|
| }
|
|
|
| -/* A helper for iterate_over_all_matching_symtabs that is passed as a
|
| - callback to the expand_symtabs_matching method. */
|
| +/* Does P represent the end of a quote-enclosed linespec? */
|
|
|
| static int
|
| -iterate_name_matcher (const struct language_defn *language,
|
| - const char *name, void *d)
|
| +is_closing_quote_enclosed (const char *p)
|
| {
|
| - const char **dname = d;
|
| -
|
| - if (language->la_symbol_name_compare (name, *dname) == 0)
|
| - return 1;
|
| - return 0;
|
| + if (strchr (linespec_quote_characters, *p))
|
| + ++p;
|
| + p = skip_spaces ((char *) p);
|
| + return (*p == '\0' || linespec_lexer_lex_keyword (p));
|
| }
|
|
|
| -/* A helper that walks over all matching symtabs in all objfiles and
|
| - calls CALLBACK for each symbol matching NAME. If SEARCH_PSPACE is
|
| - not NULL, then the search is restricted to just that program
|
| - space. */
|
| +/* Find the end of the parameter list that starts with *INPUT.
|
| + This helper function assists with lexing string segments
|
| + which might contain valid (non-terminating) commas. */
|
|
|
| -static void
|
| -iterate_over_all_matching_symtabs (const char *name,
|
| - const domain_enum domain,
|
| - int (*callback) (struct symbol *, void *),
|
| - void *data,
|
| - struct program_space *search_pspace)
|
| +static char *
|
| +find_parameter_list_end (char *input)
|
| {
|
| - struct objfile *objfile;
|
| - struct program_space *pspace;
|
| -
|
| - ALL_PSPACES (pspace)
|
| - {
|
| - if (search_pspace != NULL && search_pspace != pspace)
|
| - continue;
|
| - if (pspace->executing_startup)
|
| - continue;
|
| + char end_char, start_char;
|
| + int depth;
|
| + char *p;
|
|
|
| - set_current_program_space (pspace);
|
| + start_char = *input;
|
| + if (start_char == '(')
|
| + end_char = ')';
|
| + else if (start_char == '<')
|
| + end_char = '>';
|
| + else
|
| + return NULL;
|
|
|
| - ALL_OBJFILES (objfile)
|
| + p = input;
|
| + depth = 0;
|
| + while (*p)
|
| {
|
| - struct symtab *symtab;
|
| -
|
| - if (objfile->sf)
|
| - objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
|
| - iterate_name_matcher,
|
| - ALL_DOMAIN,
|
| - &name);
|
| -
|
| - ALL_OBJFILE_SYMTABS (objfile, symtab)
|
| + if (*p == start_char)
|
| + ++depth;
|
| + else if (*p == end_char)
|
| {
|
| - if (symtab->primary)
|
| + if (--depth == 0)
|
| {
|
| - struct block *block;
|
| -
|
| - block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
|
| - LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
|
| + ++p;
|
| + break;
|
| }
|
| }
|
| + ++p;
|
| }
|
| - }
|
| +
|
| + return p;
|
| }
|
|
|
| -/* Returns the block to be used for symbol searches for the given SYMTAB,
|
| - which may be NULL. */
|
|
|
| -static struct block *
|
| -get_search_block (struct symtab *symtab)
|
| +/* Lex a string from the input in PARSER. */
|
| +
|
| +static linespec_token
|
| +linespec_lexer_lex_string (linespec_parser *parser)
|
| {
|
| - struct block *block;
|
| + linespec_token token;
|
| + char *start = PARSER_STREAM (parser);
|
|
|
| - if (symtab != NULL)
|
| - block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
|
| - else
|
| + token.type = LSTOKEN_STRING;
|
| +
|
| + /* If the input stream starts with a quote character, skip to the next
|
| + quote character, regardless of the content. */
|
| + if (strchr (linespec_quote_characters, *PARSER_STREAM (parser)))
|
| {
|
| - enum language save_language;
|
| + const char *end;
|
| + char quote_char = *PARSER_STREAM (parser);
|
|
|
| - /* get_selected_block can change the current language when there is
|
| - no selected frame yet. */
|
| - save_language = current_language->la_language;
|
| - block = get_selected_block (0);
|
| - set_language (save_language);
|
| - }
|
| + /* Special case: Ada operators. */
|
| + if (PARSER_STATE (parser)->language->la_language == language_ada
|
| + && quote_char == '\"')
|
| + {
|
| + int len = is_ada_operator (PARSER_STREAM (parser));
|
|
|
| - return block;
|
| -}
|
| + if (len != 0)
|
| + {
|
| + /* The input is an Ada operator. Return the quoted string
|
| + as-is. */
|
| + LS_TOKEN_STOKEN (token).ptr = PARSER_STREAM (parser);
|
| + LS_TOKEN_STOKEN (token).length = len;
|
| + PARSER_STREAM (parser) += len;
|
| + return token;
|
| + }
|
|
|
| -/* A helper for find_method. This finds all methods in type T which
|
| - match NAME. It adds resulting symbol names to RESULT_NAMES, and
|
| - adds T's direct superclasses to SUPERCLASSES. */
|
| + /* The input does not represent an Ada operator -- fall through
|
| + to normal quoted string handling. */
|
| + }
|
|
|
| -static void
|
| -find_methods (struct type *t, const char *name,
|
| - VEC (const_char_ptr) **result_names,
|
| - VEC (typep) **superclasses)
|
| -{
|
| - int i1 = 0;
|
| - int ibase;
|
| - char *class_name = type_name_no_tag (t);
|
| - char *canon;
|
| + /* Skip past the beginning quote. */
|
| + ++(PARSER_STREAM (parser));
|
|
|
| - /* Ignore this class if it doesn't have a name. This is ugly, but
|
| + /* Mark the start of the string. */
|
| + LS_TOKEN_STOKEN (token).ptr = PARSER_STREAM (parser);
|
| +
|
| + /* Skip to the ending quote. */
|
| + end = skip_quote_char (PARSER_STREAM (parser), quote_char);
|
| +
|
| + /* Error if the input did not terminate properly. */
|
| + if (end == NULL)
|
| + error (_("unmatched quote"));
|
| +
|
| + /* Skip over the ending quote and mark the length of the string. */
|
| + PARSER_STREAM (parser) = (char *) ++end;
|
| + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 2 - start;
|
| + }
|
| + else
|
| + {
|
| + char *p;
|
| +
|
| + /* Otherwise, only identifier characters are permitted.
|
| + Spaces are the exception. In general, we keep spaces,
|
| + but only if the next characters in the input do not resolve
|
| + to one of the keywords.
|
| +
|
| + This allows users to forgo quoting CV-qualifiers, template arguments,
|
| + and similar common language constructs. */
|
| +
|
| + while (1)
|
| + {
|
| + if (isspace (*PARSER_STREAM (parser)))
|
| + {
|
| + p = skip_spaces (PARSER_STREAM (parser));
|
| + /* When we get here we know we've found something followed by
|
| + a space (we skip over parens and templates below).
|
| + So if we find a keyword now, we know it is a keyword and not,
|
| + say, a function name. */
|
| + if (linespec_lexer_lex_keyword (p) != NULL)
|
| + {
|
| + LS_TOKEN_STOKEN (token).ptr = start;
|
| + LS_TOKEN_STOKEN (token).length
|
| + = PARSER_STREAM (parser) - start;
|
| + return token;
|
| + }
|
| +
|
| + /* Advance past the whitespace. */
|
| + PARSER_STREAM (parser) = p;
|
| + }
|
| +
|
| + /* If the next character is EOI or (single) ':', the
|
| + string is complete; return the token. */
|
| + if (*PARSER_STREAM (parser) == 0)
|
| + {
|
| + LS_TOKEN_STOKEN (token).ptr = start;
|
| + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - start;
|
| + return token;
|
| + }
|
| + else if (PARSER_STREAM (parser)[0] == ':')
|
| + {
|
| + /* Do not tokenize the C++ scope operator. */
|
| + if (PARSER_STREAM (parser)[1] == ':')
|
| + ++(PARSER_STREAM (parser));
|
| +
|
| + /* Do not tokenify if the input length so far is one
|
| + (i.e, a single-letter drive name) and the next character
|
| + is a directory separator. This allows Windows-style
|
| + paths to be recognized as filenames without quoting it. */
|
| + else if ((PARSER_STREAM (parser) - start) != 1
|
| + || !IS_DIR_SEPARATOR (PARSER_STREAM (parser)[1]))
|
| + {
|
| + LS_TOKEN_STOKEN (token).ptr = start;
|
| + LS_TOKEN_STOKEN (token).length
|
| + = PARSER_STREAM (parser) - start;
|
| + return token;
|
| + }
|
| + }
|
| + /* Special case: permit quote-enclosed linespecs. */
|
| + else if (parser->is_quote_enclosed
|
| + && strchr (linespec_quote_characters,
|
| + *PARSER_STREAM (parser))
|
| + && is_closing_quote_enclosed (PARSER_STREAM (parser)))
|
| + {
|
| + LS_TOKEN_STOKEN (token).ptr = start;
|
| + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - start;
|
| + return token;
|
| + }
|
| + /* Because commas may terminate a linespec and appear in
|
| + the middle of valid string input, special cases for
|
| + '<' and '(' are necessary. */
|
| + else if (*PARSER_STREAM (parser) == '<'
|
| + || *PARSER_STREAM (parser) == '(')
|
| + {
|
| + char *p;
|
| +
|
| + p = find_parameter_list_end (PARSER_STREAM (parser));
|
| + if (p != NULL)
|
| + {
|
| + PARSER_STREAM (parser) = p;
|
| + continue;
|
| + }
|
| + }
|
| + /* Commas are terminators, but not if they are part of an
|
| + operator name. */
|
| + else if (*PARSER_STREAM (parser) == ',')
|
| + {
|
| + if ((PARSER_STATE (parser)->language->la_language
|
| + == language_cplus)
|
| + && (PARSER_STREAM (parser) - start) > 8
|
| + /* strlen ("operator") */)
|
| + {
|
| + char *p = strstr (start, "operator");
|
| +
|
| + if (p != NULL && is_operator_name (p))
|
| + {
|
| + /* This is an operator name. Keep going. */
|
| + ++(PARSER_STREAM (parser));
|
| + continue;
|
| + }
|
| + }
|
| +
|
| + /* Comma terminates the string. */
|
| + LS_TOKEN_STOKEN (token).ptr = start;
|
| + LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - start;
|
| + return token;
|
| + }
|
| +
|
| + /* Advance the stream. */
|
| + ++(PARSER_STREAM (parser));
|
| + }
|
| + }
|
| +
|
| + return token;
|
| +}
|
| +
|
| +/* Lex a single linespec token from PARSER. */
|
| +
|
| +static linespec_token
|
| +linespec_lexer_lex_one (linespec_parser *parser)
|
| +{
|
| + const char *keyword;
|
| +
|
| + if (parser->lexer.current.type == LSTOKEN_CONSUMED)
|
| + {
|
| + /* Skip any whitespace. */
|
| + PARSER_STREAM (parser) = skip_spaces (PARSER_STREAM (parser));
|
| +
|
| + /* Check for a keyword, they end the linespec. */
|
| + keyword = NULL;
|
| + if (parser->keyword_ok)
|
| + keyword = linespec_lexer_lex_keyword (PARSER_STREAM (parser));
|
| + if (keyword != NULL)
|
| + {
|
| + parser->lexer.current.type = LSTOKEN_KEYWORD;
|
| + LS_TOKEN_KEYWORD (parser->lexer.current) = keyword;
|
| + return parser->lexer.current;
|
| + }
|
| +
|
| + /* Handle other tokens. */
|
| + switch (*PARSER_STREAM (parser))
|
| + {
|
| + case 0:
|
| + parser->lexer.current.type = LSTOKEN_EOI;
|
| + break;
|
| +
|
| + case '+': case '-':
|
| + case '0': case '1': case '2': case '3': case '4':
|
| + case '5': case '6': case '7': case '8': case '9':
|
| + if (!linespec_lexer_lex_number (parser, &(parser->lexer.current)))
|
| + parser->lexer.current = linespec_lexer_lex_string (parser);
|
| + break;
|
| +
|
| + case ':':
|
| + /* If we have a scope operator, lex the input as a string.
|
| + Otherwise, return LSTOKEN_COLON. */
|
| + if (PARSER_STREAM (parser)[1] == ':')
|
| + parser->lexer.current = linespec_lexer_lex_string (parser);
|
| + else
|
| + {
|
| + parser->lexer.current.type = LSTOKEN_COLON;
|
| + ++(PARSER_STREAM (parser));
|
| + }
|
| + break;
|
| +
|
| + case '\'': case '\"':
|
| + /* Special case: permit quote-enclosed linespecs. */
|
| + if (parser->is_quote_enclosed
|
| + && is_closing_quote_enclosed (PARSER_STREAM (parser)))
|
| + {
|
| + ++(PARSER_STREAM (parser));
|
| + parser->lexer.current.type = LSTOKEN_EOI;
|
| + }
|
| + else
|
| + parser->lexer.current = linespec_lexer_lex_string (parser);
|
| + break;
|
| +
|
| + case ',':
|
| + parser->lexer.current.type = LSTOKEN_COMMA;
|
| + LS_TOKEN_STOKEN (parser->lexer.current).ptr
|
| + = PARSER_STREAM (parser);
|
| + LS_TOKEN_STOKEN (parser->lexer.current).length = 1;
|
| + ++(PARSER_STREAM (parser));
|
| + break;
|
| +
|
| + default:
|
| + /* If the input is not a number, it must be a string.
|
| + [Keywords were already considered above.] */
|
| + parser->lexer.current = linespec_lexer_lex_string (parser);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return parser->lexer.current;
|
| +}
|
| +
|
| +/* Consume the current token and return the next token in PARSER's
|
| + input stream. */
|
| +
|
| +static linespec_token
|
| +linespec_lexer_consume_token (linespec_parser *parser)
|
| +{
|
| + parser->lexer.current.type = LSTOKEN_CONSUMED;
|
| + return linespec_lexer_lex_one (parser);
|
| +}
|
| +
|
| +/* Return the next token without consuming the current token. */
|
| +
|
| +static linespec_token
|
| +linespec_lexer_peek_token (linespec_parser *parser)
|
| +{
|
| + linespec_token next;
|
| + char *saved_stream = PARSER_STREAM (parser);
|
| + linespec_token saved_token = parser->lexer.current;
|
| +
|
| + next = linespec_lexer_consume_token (parser);
|
| + PARSER_STREAM (parser) = saved_stream;
|
| + parser->lexer.current = saved_token;
|
| + return next;
|
| +}
|
| +
|
| +/* Helper functions. */
|
| +
|
| +/* Add SAL to SALS. */
|
| +
|
| +static void
|
| +add_sal_to_sals_basic (struct symtabs_and_lines *sals,
|
| + struct symtab_and_line *sal)
|
| +{
|
| + ++sals->nelts;
|
| + sals->sals = xrealloc (sals->sals, sals->nelts * sizeof (sals->sals[0]));
|
| + sals->sals[sals->nelts - 1] = *sal;
|
| +}
|
| +
|
| +/* Add SAL to SALS, and also update SELF->CANONICAL_NAMES to reflect
|
| + the new sal, if needed. If not NULL, SYMNAME is the name of the
|
| + symbol to use when constructing the new canonical name. */
|
| +
|
| +static void
|
| +add_sal_to_sals (struct linespec_state *self,
|
| + struct symtabs_and_lines *sals,
|
| + struct symtab_and_line *sal,
|
| + const char *symname)
|
| +{
|
| + add_sal_to_sals_basic (sals, sal);
|
| +
|
| + if (self->canonical)
|
| + {
|
| + char *canonical_name = NULL;
|
| +
|
| + self->canonical_names = xrealloc (self->canonical_names,
|
| + sals->nelts * sizeof (char *));
|
| + if (sal->symtab && sal->symtab->filename)
|
| + {
|
| + char *filename = sal->symtab->filename;
|
| +
|
| + /* Note that the filter doesn't have to be a valid linespec
|
| + input. We only apply the ":LINE" treatment to Ada for
|
| + the time being. */
|
| + if (symname != NULL && sal->line != 0
|
| + && self->language->la_language == language_ada)
|
| + canonical_name = xstrprintf ("%s:%s:%d", filename, symname,
|
| + sal->line);
|
| + else if (symname != NULL)
|
| + canonical_name = xstrprintf ("%s:%s", filename, symname);
|
| + else
|
| + canonical_name = xstrprintf ("%s:%d", filename, sal->line);
|
| + }
|
| +
|
| + self->canonical_names[sals->nelts - 1] = canonical_name;
|
| + }
|
| +}
|
| +
|
| +/* A hash function for address_entry. */
|
| +
|
| +static hashval_t
|
| +hash_address_entry (const void *p)
|
| +{
|
| + const struct address_entry *aep = p;
|
| + hashval_t hash;
|
| +
|
| + hash = iterative_hash_object (aep->pspace, 0);
|
| + return iterative_hash_object (aep->addr, hash);
|
| +}
|
| +
|
| +/* An equality function for address_entry. */
|
| +
|
| +static int
|
| +eq_address_entry (const void *a, const void *b)
|
| +{
|
| + const struct address_entry *aea = a;
|
| + const struct address_entry *aeb = b;
|
| +
|
| + return aea->pspace == aeb->pspace && aea->addr == aeb->addr;
|
| +}
|
| +
|
| +/* Check whether the address, represented by PSPACE and ADDR, is
|
| + already in the set. If so, return 0. Otherwise, add it and return
|
| + 1. */
|
| +
|
| +static int
|
| +maybe_add_address (htab_t set, struct program_space *pspace, CORE_ADDR addr)
|
| +{
|
| + struct address_entry e, *p;
|
| + void **slot;
|
| +
|
| + e.pspace = pspace;
|
| + e.addr = addr;
|
| + slot = htab_find_slot (set, &e, INSERT);
|
| + if (*slot)
|
| + return 0;
|
| +
|
| + p = XNEW (struct address_entry);
|
| + memcpy (p, &e, sizeof (struct address_entry));
|
| + *slot = p;
|
| +
|
| + return 1;
|
| +}
|
| +
|
| +/* A callback function and the additional data to call it with. */
|
| +
|
| +struct symbol_and_data_callback
|
| +{
|
| + /* The callback to use. */
|
| + symbol_found_callback_ftype *callback;
|
| +
|
| + /* Data to be passed to the callback. */
|
| + void *data;
|
| +};
|
| +
|
| +/* A helper for iterate_over_all_matching_symtabs that is used to
|
| + restrict calls to another callback to symbols representing inline
|
| + symbols only. */
|
| +
|
| +static int
|
| +iterate_inline_only (struct symbol *sym, void *d)
|
| +{
|
| + if (SYMBOL_INLINED (sym))
|
| + {
|
| + struct symbol_and_data_callback *cad = d;
|
| +
|
| + return cad->callback (sym, cad->data);
|
| + }
|
| + return 1; /* Continue iterating. */
|
| +}
|
| +
|
| +/* Some data for the expand_symtabs_matching callback. */
|
| +
|
| +struct symbol_matcher_data
|
| +{
|
| + /* The lookup name against which symbol name should be compared. */
|
| + const char *lookup_name;
|
| +
|
| + /* The routine to be used for comparison. */
|
| + symbol_name_cmp_ftype symbol_name_cmp;
|
| +};
|
| +
|
| +/* A helper for iterate_over_all_matching_symtabs that is passed as a
|
| + callback to the expand_symtabs_matching method. */
|
| +
|
| +static int
|
| +iterate_name_matcher (const char *name, void *d)
|
| +{
|
| + const struct symbol_matcher_data *data = d;
|
| +
|
| + if (data->symbol_name_cmp (name, data->lookup_name) == 0)
|
| + return 1; /* Expand this symbol's symbol table. */
|
| + return 0; /* Skip this symbol. */
|
| +}
|
| +
|
| +/* A helper that walks over all matching symtabs in all objfiles and
|
| + calls CALLBACK for each symbol matching NAME. If SEARCH_PSPACE is
|
| + not NULL, then the search is restricted to just that program
|
| + space. If INCLUDE_INLINE is nonzero then symbols representing
|
| + inlined instances of functions will be included in the result. */
|
| +
|
| +static void
|
| +iterate_over_all_matching_symtabs (struct linespec_state *state,
|
| + const char *name,
|
| + const domain_enum domain,
|
| + symbol_found_callback_ftype *callback,
|
| + void *data,
|
| + struct program_space *search_pspace,
|
| + int include_inline)
|
| +{
|
| + struct objfile *objfile;
|
| + struct program_space *pspace;
|
| + struct symbol_matcher_data matcher_data;
|
| +
|
| + matcher_data.lookup_name = name;
|
| + matcher_data.symbol_name_cmp =
|
| + state->language->la_get_symbol_name_cmp != NULL
|
| + ? state->language->la_get_symbol_name_cmp (name)
|
| + : strcmp_iw;
|
| +
|
| + ALL_PSPACES (pspace)
|
| + {
|
| + if (search_pspace != NULL && search_pspace != pspace)
|
| + continue;
|
| + if (pspace->executing_startup)
|
| + continue;
|
| +
|
| + set_current_program_space (pspace);
|
| +
|
| + ALL_OBJFILES (objfile)
|
| + {
|
| + struct symtab *symtab;
|
| +
|
| + if (objfile->sf)
|
| + objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
|
| + iterate_name_matcher,
|
| + ALL_DOMAIN,
|
| + &matcher_data);
|
| +
|
| + ALL_OBJFILE_PRIMARY_SYMTABS (objfile, symtab)
|
| + {
|
| + struct block *block;
|
| +
|
| + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
|
| + LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
|
| +
|
| + if (include_inline)
|
| + {
|
| + struct symbol_and_data_callback cad = { callback, data };
|
| + int i;
|
| +
|
| + for (i = FIRST_LOCAL_BLOCK;
|
| + i < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (symtab)); i++)
|
| + {
|
| + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), i);
|
| + LA_ITERATE_OVER_SYMBOLS (block, name, domain,
|
| + iterate_inline_only, &cad);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/* Returns the block to be used for symbol searches for the given SYMTAB,
|
| + which may be NULL. */
|
| +
|
| +static struct block *
|
| +get_search_block (struct symtab *symtab)
|
| +{
|
| + struct block *block;
|
| +
|
| + if (symtab != NULL)
|
| + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
|
| + else
|
| + {
|
| + enum language save_language;
|
| +
|
| + /* get_selected_block can change the current language when there is
|
| + no selected frame yet. */
|
| + save_language = current_language->la_language;
|
| + block = get_selected_block (0);
|
| + set_language (save_language);
|
| + }
|
| +
|
| + return block;
|
| +}
|
| +
|
| +/* A helper for find_method. This finds all methods in type T which
|
| + match NAME. It adds matching symbol names to RESULT_NAMES, and
|
| + adds T's direct superclasses to SUPERCLASSES. */
|
| +
|
| +static void
|
| +find_methods (struct type *t, const char *name,
|
| + VEC (const_char_ptr) **result_names,
|
| + VEC (typep) **superclasses)
|
| +{
|
| + int i1 = 0;
|
| + int ibase;
|
| + const char *class_name = type_name_no_tag (t);
|
| +
|
| + /* Ignore this class if it doesn't have a name. This is ugly, but
|
| unless we figure out how to get the physname without the name of
|
| the class, then the loop can't do any good. */
|
| if (class_name)
|
| @@ -439,7 +1091,7 @@ find_methods (struct type *t, const char *name,
|
| method_counter >= 0;
|
| --method_counter)
|
| {
|
| - char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
|
| + const char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
|
| char dem_opname[64];
|
|
|
| if (strncmp (method_name, "__", 2) == 0 ||
|
| @@ -483,14 +1135,14 @@ find_methods (struct type *t, const char *name,
|
| strings. Also, ignore the char within a template name, like a ','
|
| within foo<int, int>. */
|
|
|
| -static char *
|
| -find_toplevel_char (char *s, char c)
|
| +static const char *
|
| +find_toplevel_char (const char *s, char c)
|
| {
|
| int quoted = 0; /* zero if we're not in quotes;
|
| '"' if we're in a double-quoted string;
|
| '\'' if we're in a single-quoted string. */
|
| int depth = 0; /* Number of unclosed parens we've seen. */
|
| - char *scan;
|
| + const char *scan;
|
|
|
| for (scan = s; *scan; scan++)
|
| {
|
| @@ -514,23 +1166,34 @@ find_toplevel_char (char *s, char c)
|
| return 0;
|
| }
|
|
|
| -/* Determines if the gives string corresponds to an Objective-C method
|
| - representation, such as -[Foo bar:] or +[Foo bar]. Objective-C symbols
|
| - are allowed to have spaces and parentheses in them. */
|
| +/* The string equivalent of find_toplevel_char. Returns a pointer
|
| + to the location of NEEDLE in HAYSTACK, ignoring any occurrences
|
| + inside "()" and "<>". Returns NULL if NEEDLE was not found. */
|
|
|
| -static int
|
| -is_objc_method_format (const char *s)
|
| +static const char *
|
| +find_toplevel_string (const char *haystack, const char *needle)
|
| {
|
| - if (s == NULL || *s == '\0')
|
| - return 0;
|
| - /* Handle arguments with the format FILENAME:SYMBOL. */
|
| - if ((s[0] == ':') && (strchr ("+-", s[1]) != NULL)
|
| - && (s[2] == '[') && strchr(s, ']'))
|
| - return 1;
|
| - /* Handle arguments that are just SYMBOL. */
|
| - else if ((strchr ("+-", s[0]) != NULL) && (s[1] == '[') && strchr(s, ']'))
|
| - return 1;
|
| - return 0;
|
| + const char *s = haystack;
|
| +
|
| + do
|
| + {
|
| + s = find_toplevel_char (s, *needle);
|
| +
|
| + if (s != NULL)
|
| + {
|
| + /* Found first char in HAYSTACK; check rest of string. */
|
| + if (strncmp (s, needle, strlen (needle)) == 0)
|
| + return s;
|
| +
|
| + /* Didn't find it; loop over HAYSTACK, looking for the next
|
| + instance of the first character of NEEDLE. */
|
| + ++s;
|
| + }
|
| + }
|
| + while (s != NULL && *s != '\0');
|
| +
|
| + /* NEEDLE was not found in HAYSTACK. */
|
| + return NULL;
|
| }
|
|
|
| /* Given FILTERS, a list of canonical names, filter the sals in RESULT
|
| @@ -634,178 +1297,690 @@ decode_line_2 (struct linespec_state *self,
|
| return;
|
| }
|
|
|
| - printf_unfiltered (_("[0] cancel\n[1] all\n"));
|
| - for (i = 0; VEC_iterate (const_char_ptr, item_names, i, iter); ++i)
|
| - printf_unfiltered ("[%d] %s\n", i + 2, iter);
|
| + /* Sort the list of method names alphabetically. */
|
| + qsort (VEC_address (const_char_ptr, item_names),
|
| + VEC_length (const_char_ptr, item_names),
|
| + sizeof (const_char_ptr), compare_strings);
|
| +
|
| + printf_unfiltered (_("[0] cancel\n[1] all\n"));
|
| + for (i = 0; VEC_iterate (const_char_ptr, item_names, i, iter); ++i)
|
| + printf_unfiltered ("[%d] %s\n", i + 2, iter);
|
| +
|
| + prompt = getenv ("PS2");
|
| + if (prompt == NULL)
|
| + {
|
| + prompt = "> ";
|
| + }
|
| + args = command_line_input (prompt, 0, "overload-choice");
|
| +
|
| + if (args == 0 || *args == 0)
|
| + error_no_arg (_("one or more choice numbers"));
|
| +
|
| + init_number_or_range (&state, args);
|
| + while (!state.finished)
|
| + {
|
| + int num;
|
| +
|
| + num = get_number_or_range (&state);
|
| +
|
| + if (num == 0)
|
| + error (_("canceled"));
|
| + else if (num == 1)
|
| + {
|
| + /* We intentionally make this result in a single breakpoint,
|
| + contrary to what older versions of gdb did. The
|
| + rationale is that this lets a user get the
|
| + multiple_symbols_all behavior even with the 'ask'
|
| + setting; and he can get separate breakpoints by entering
|
| + "2-57" at the query. */
|
| + do_cleanups (old_chain);
|
| + convert_results_to_lsals (self, result);
|
| + return;
|
| + }
|
| +
|
| + num -= 2;
|
| + if (num >= VEC_length (const_char_ptr, item_names))
|
| + printf_unfiltered (_("No choice number %d.\n"), num);
|
| + else
|
| + {
|
| + const char *elt = VEC_index (const_char_ptr, item_names, num);
|
| +
|
| + if (elt != NULL)
|
| + {
|
| + VEC_safe_push (const_char_ptr, filters, elt);
|
| + VEC_replace (const_char_ptr, item_names, num, NULL);
|
| + }
|
| + else
|
| + {
|
| + printf_unfiltered (_("duplicate request for %d ignored.\n"),
|
| + num);
|
| + }
|
| + }
|
| + }
|
| +
|
| + filter_results (self, result, filters);
|
| + do_cleanups (old_chain);
|
| +}
|
| +
|
| +
|
| +
|
| +/* The parser of linespec itself. */
|
| +
|
| +/* Throw an appropriate error when SYMBOL is not found (optionally in
|
| + FILENAME). */
|
| +
|
| +static void ATTRIBUTE_NORETURN
|
| +symbol_not_found_error (char *symbol, char *filename)
|
| +{
|
| + if (symbol == NULL)
|
| + symbol = "";
|
| +
|
| + if (!have_full_symbols ()
|
| + && !have_partial_symbols ()
|
| + && !have_minimal_symbols ())
|
| + throw_error (NOT_FOUND_ERROR,
|
| + _("No symbol table is loaded. Use the \"file\" command."));
|
| +
|
| + /* If SYMBOL starts with '$', the user attempted to either lookup
|
| + a function/variable in his code starting with '$' or an internal
|
| + variable of that name. Since we do not know which, be concise and
|
| + explain both possibilities. */
|
| + if (*symbol == '$')
|
| + {
|
| + if (filename)
|
| + throw_error (NOT_FOUND_ERROR,
|
| + _("Undefined convenience variable or function \"%s\" "
|
| + "not defined in \"%s\"."), symbol, filename);
|
| + else
|
| + throw_error (NOT_FOUND_ERROR,
|
| + _("Undefined convenience variable or function \"%s\" "
|
| + "not defined."), symbol);
|
| + }
|
| + else
|
| + {
|
| + if (filename)
|
| + throw_error (NOT_FOUND_ERROR,
|
| + _("Function \"%s\" not defined in \"%s\"."),
|
| + symbol, filename);
|
| + else
|
| + throw_error (NOT_FOUND_ERROR,
|
| + _("Function \"%s\" not defined."), symbol);
|
| + }
|
| +}
|
| +
|
| +/* Throw an appropriate error when an unexpected token is encountered
|
| + in the input. */
|
| +
|
| +static void ATTRIBUTE_NORETURN
|
| +unexpected_linespec_error (linespec_parser *parser)
|
| +{
|
| + linespec_token token;
|
| + static const char * token_type_strings[]
|
| + = {"keyword", "colon", "string", "number", "comma", "end of input"};
|
| +
|
| + /* Get the token that generated the error. */
|
| + token = linespec_lexer_lex_one (parser);
|
| +
|
| + /* Finally, throw the error. */
|
| + if (token.type == LSTOKEN_STRING || token.type == LSTOKEN_NUMBER
|
| + || token.type == LSTOKEN_KEYWORD)
|
| + {
|
| + char *string;
|
| + struct cleanup *cleanup;
|
| +
|
| + string = copy_token_string (token);
|
| + cleanup = make_cleanup (xfree, string);
|
| + throw_error (GENERIC_ERROR,
|
| + _("malformed linespec error: unexpected %s, \"%s\""),
|
| + token_type_strings[token.type], string);
|
| + }
|
| + else
|
| + throw_error (GENERIC_ERROR,
|
| + _("malformed linespec error: unexpected %s"),
|
| + token_type_strings[token.type]);
|
| +}
|
| +
|
| +/* Parse and return a line offset in STRING. */
|
| +
|
| +static struct line_offset
|
| +linespec_parse_line_offset (char *string)
|
| +{
|
| + struct line_offset line_offset = {0, LINE_OFFSET_NONE};
|
| +
|
| + if (*string == '+')
|
| + {
|
| + line_offset.sign = LINE_OFFSET_PLUS;
|
| + ++string;
|
| + }
|
| + else if (*string == '-')
|
| + {
|
| + line_offset.sign = LINE_OFFSET_MINUS;
|
| + ++string;
|
| + }
|
| +
|
| + /* Right now, we only allow base 10 for offsets. */
|
| + line_offset.offset = atoi (string);
|
| + return line_offset;
|
| +}
|
| +
|
| +/* Parse the basic_spec in PARSER's input. */
|
| +
|
| +static void
|
| +linespec_parse_basic (linespec_parser *parser)
|
| +{
|
| + char *name;
|
| + linespec_token token;
|
| + VEC (symbolp) *symbols, *labels;
|
| + VEC (minsym_and_objfile_d) *minimal_symbols;
|
| + struct cleanup *cleanup;
|
| +
|
| + /* Get the next token. */
|
| + token = linespec_lexer_lex_one (parser);
|
| +
|
| + /* If it is EOI or KEYWORD, issue an error. */
|
| + if (token.type == LSTOKEN_KEYWORD || token.type == LSTOKEN_EOI)
|
| + unexpected_linespec_error (parser);
|
| + /* If it is a LSTOKEN_NUMBER, we have an offset. */
|
| + else if (token.type == LSTOKEN_NUMBER)
|
| + {
|
| + /* 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);
|
| + do_cleanups (cleanup);
|
| +
|
| + /* Get the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
| +
|
| + /* If the next token is a comma, stop parsing and return. */
|
| + if (token.type == LSTOKEN_COMMA)
|
| + return;
|
| +
|
| + /* If the next token is anything but EOI or KEYWORD, issue
|
| + an error. */
|
| + if (token.type != LSTOKEN_KEYWORD && token.type != LSTOKEN_EOI)
|
| + unexpected_linespec_error (parser);
|
| + }
|
| +
|
| + if (token.type == LSTOKEN_KEYWORD || token.type == LSTOKEN_EOI)
|
| + return;
|
| +
|
| + /* Next token must be LSTOKEN_STRING. */
|
| + if (token.type != LSTOKEN_STRING)
|
| + unexpected_linespec_error (parser);
|
| +
|
| + /* The current token will contain the name of a function, method,
|
| + or label. */
|
| + name = copy_token_string (token);
|
| + cleanup = make_cleanup (xfree, name);
|
| +
|
| + /* Try looking it up as a function/method. */
|
| + find_linespec_symbols (PARSER_STATE (parser),
|
| + PARSER_RESULT (parser)->file_symtabs, name,
|
| + &symbols, &minimal_symbols);
|
| +
|
| + if (symbols != NULL || minimal_symbols != NULL)
|
| + {
|
| + PARSER_RESULT (parser)->function_symbols = symbols;
|
| + PARSER_RESULT (parser)->minimal_symbols = minimal_symbols;
|
| + PARSER_RESULT (parser)->function_name = name;
|
| + symbols = NULL;
|
| + discard_cleanups (cleanup);
|
| + }
|
| + else
|
| + {
|
| + /* NAME was not a function or a method. So it must be a label
|
| + name. */
|
| + labels = find_label_symbols (PARSER_STATE (parser), NULL,
|
| + &symbols, name);
|
| + if (labels != NULL)
|
| + {
|
| + PARSER_RESULT (parser)->labels.label_symbols = labels;
|
| + PARSER_RESULT (parser)->labels.function_symbols = symbols;
|
| + PARSER_RESULT (parser)->label_name = name;
|
| + symbols = NULL;
|
| + discard_cleanups (cleanup);
|
| + }
|
| + else
|
| + {
|
| + /* The name is also not a label. Abort parsing. Do not throw
|
| + 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;
|
| + discard_cleanups (cleanup);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + /* Get the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
| +
|
| + if (token.type == LSTOKEN_COLON)
|
| + {
|
| + /* User specified a label or a lineno. */
|
| + token = linespec_lexer_consume_token (parser);
|
| +
|
| + if (token.type == LSTOKEN_NUMBER)
|
| + {
|
| + /* User specified an offset. 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);
|
| + do_cleanups (cleanup);
|
| +
|
| + /* Ge the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
| + }
|
| + else if (token.type == LSTOKEN_STRING)
|
| + {
|
| + /* Grab a copy of the label's name and look it up. */
|
| + name = copy_token_string (token);
|
| + cleanup = make_cleanup (xfree, name);
|
| + labels = find_label_symbols (PARSER_STATE (parser),
|
| + PARSER_RESULT (parser)->function_symbols,
|
| + &symbols, name);
|
| +
|
| + if (labels != NULL)
|
| + {
|
| + PARSER_RESULT (parser)->labels.label_symbols = labels;
|
| + PARSER_RESULT (parser)->labels.function_symbols = symbols;
|
| + PARSER_RESULT (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);
|
| + }
|
| +
|
| + /* Check for a line offset. */
|
| + token = linespec_lexer_consume_token (parser);
|
| + if (token.type == LSTOKEN_COLON)
|
| + {
|
| + /* Get the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
| +
|
| + /* It must be a line offset. */
|
| + if (token.type != LSTOKEN_NUMBER)
|
| + unexpected_linespec_error (parser);
|
|
|
| - prompt = getenv ("PS2");
|
| - if (prompt == NULL)
|
| - {
|
| - prompt = "> ";
|
| + /* Record the lione 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);
|
| + do_cleanups (cleanup);
|
| +
|
| + /* Get the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
| + }
|
| + }
|
| + else
|
| + {
|
| + /* Trailing ':' in the input. Issue an error. */
|
| + unexpected_linespec_error (parser);
|
| + }
|
| }
|
| - args = command_line_input (prompt, 0, "overload-choice");
|
| +}
|
|
|
| - if (args == 0 || *args == 0)
|
| - error_no_arg (_("one or more choice numbers"));
|
| +/* Canonicalize the linespec contained in LS. The result is saved into
|
| + STATE->canonical. */
|
|
|
| - init_number_or_range (&state, args);
|
| - while (!state.finished)
|
| +static void
|
| +canonicalize_linespec (struct linespec_state *state, linespec_p ls)
|
| +{
|
| + /* If canonicalization was not requested, no need to do anything. */
|
| + if (!state->canonical)
|
| + return;
|
| +
|
| + /* Shortcut expressions, which can only appear by themselves. */
|
| + if (ls->expression != NULL)
|
| + state->canonical->addr_string = xstrdup (ls->expression);
|
| + else
|
| {
|
| - int num;
|
| + struct ui_file *buf;
|
| + int need_colon = 0;
|
|
|
| - num = get_number_or_range (&state);
|
| + buf = mem_fileopen ();
|
| + if (ls->source_filename)
|
| + {
|
| + fputs_unfiltered (ls->source_filename, buf);
|
| + need_colon = 1;
|
| + }
|
|
|
| - if (num == 0)
|
| - error (_("canceled"));
|
| - else if (num == 1)
|
| + if (ls->function_name)
|
| {
|
| - /* We intentionally make this result in a single breakpoint,
|
| - contrary to what older versions of gdb did. The
|
| - rationale is that this lets a user get the
|
| - multiple_symbols_all behavior even with the 'ask'
|
| - setting; and he can get separate breakpoints by entering
|
| - "2-57" at the query. */
|
| - do_cleanups (old_chain);
|
| - convert_results_to_lsals (self, result);
|
| - return;
|
| + if (need_colon)
|
| + fputc_unfiltered (':', buf);
|
| + fputs_unfiltered (ls->function_name, buf);
|
| + need_colon = 1;
|
| }
|
|
|
| - num -= 2;
|
| - if (num >= VEC_length (const_char_ptr, item_names))
|
| - printf_unfiltered (_("No choice number %d.\n"), num);
|
| - else
|
| + if (ls->label_name)
|
| {
|
| - const char *elt = VEC_index (const_char_ptr, item_names, num);
|
| + if (need_colon)
|
| + fputc_unfiltered (':', buf);
|
|
|
| - if (elt != NULL)
|
| - {
|
| - VEC_safe_push (const_char_ptr, filters, elt);
|
| - VEC_replace (const_char_ptr, item_names, num, NULL);
|
| - }
|
| - else
|
| + if (ls->function_name == NULL)
|
| {
|
| - printf_unfiltered (_("duplicate request for %d ignored.\n"),
|
| - num);
|
| + struct symbol *s;
|
| +
|
| + /* No function was specified, so add the symbol name. */
|
| + gdb_assert (ls->labels.function_symbols != NULL
|
| + && (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);
|
| }
|
| +
|
| + fputs_unfiltered (ls->label_name, buf);
|
| + need_colon = 1;
|
| + state->canonical->special_display = 1;
|
| }
|
| - }
|
|
|
| - filter_results (self, result, filters);
|
| - do_cleanups (old_chain);
|
| + 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);
|
| + }
|
| +
|
| + state->canonical->addr_string = ui_file_xstrdup (buf, NULL);
|
| + ui_file_delete (buf);
|
| + }
|
| }
|
|
|
| -/* Valid delimiters for linespec keywords "if", "thread" or "task". */
|
| +/* Given a line offset in LS, construct the relevant SALs. */
|
|
|
| -static int
|
| -is_linespec_boundary (char c)
|
| +static struct symtabs_and_lines
|
| +create_sals_line_offset (struct linespec_state *self,
|
| + linespec_p ls)
|
| {
|
| - return c == ' ' || c == '\t' || c == '\0' || c == ',';
|
| -}
|
| + struct symtabs_and_lines values;
|
| + struct symtab_and_line val;
|
| + int use_default = 0;
|
|
|
| -/* A helper function for decode_line_1 and friends which skips P
|
| - past any method overload information at the beginning of P, e.g.,
|
| - "(const struct foo *)".
|
| + init_sal (&val);
|
| + values.sals = NULL;
|
| + values.nelts = 0;
|
|
|
| - This function assumes that P has already been validated to contain
|
| - overload information, and it will assert if *P != '('. */
|
| -static char *
|
| -find_method_overload_end (char *p)
|
| -{
|
| - int depth = 0;
|
| + /* This is where we need to make sure we have good defaults.
|
| + We must guarantee that this section of code is never executed
|
| + when we are called with just a function anme, since
|
| + set_default_source_symtab_and_line uses
|
| + select_source_symtab that calls us with such an argument. */
|
|
|
| - gdb_assert (*p == '(');
|
| + if (VEC_length (symtab_p, ls->file_symtabs) == 1
|
| + && VEC_index (symtab_p, ls->file_symtabs, 0) == NULL)
|
| + {
|
| + set_current_program_space (self->program_space);
|
|
|
| - while (*p)
|
| + /* Make sure we have at least a default source line. */
|
| + set_default_source_symtab_and_line ();
|
| + initialize_defaults (&self->default_symtab, &self->default_line);
|
| + VEC_pop (symtab_p, ls->file_symtabs);
|
| + VEC_free (symtab_p, ls->file_symtabs);
|
| + ls->file_symtabs
|
| + = collect_symtabs_from_filename (self->default_symtab->filename);
|
| + use_default = 1;
|
| + }
|
| +
|
| + val.line = ls->line_offset.offset;
|
| + switch (ls->line_offset.sign)
|
| {
|
| - if (*p == '(')
|
| - ++depth;
|
| - else if (*p == ')')
|
| + case LINE_OFFSET_PLUS:
|
| + if (ls->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)
|
| + val.line = 15;
|
| + if (use_default)
|
| + val.line = self->default_line - val.line;
|
| + else
|
| + val.line = -val.line;
|
| + break;
|
| +
|
| + case LINE_OFFSET_NONE:
|
| + break; /* No need to adjust val.line. */
|
| + }
|
| +
|
| + if (self->list_mode)
|
| + decode_digits_list_mode (self, ls, &values, val);
|
| + else
|
| + {
|
| + struct linetable_entry *best_entry = NULL;
|
| + int *filter;
|
| + struct block **blocks;
|
| + struct cleanup *cleanup;
|
| + struct symtabs_and_lines intermediate_results;
|
| + int i, j;
|
| +
|
| + intermediate_results.sals = NULL;
|
| + intermediate_results.nelts = 0;
|
| +
|
| + decode_digits_ordinary (self, ls, val.line, &intermediate_results,
|
| + &best_entry);
|
| + if (intermediate_results.nelts == 0 && best_entry != NULL)
|
| + decode_digits_ordinary (self, ls, best_entry->line,
|
| + &intermediate_results, &best_entry);
|
| +
|
| + cleanup = make_cleanup (xfree, intermediate_results.sals);
|
| +
|
| + /* For optimized code, the compiler can scatter one source line
|
| + across disjoint ranges of PC values, even when no duplicate
|
| + functions or inline functions are involved. For example,
|
| + 'for (;;)' inside a non-template, non-inline, and non-ctor-or-dtor
|
| + function can result in two PC ranges. In this case, we don't
|
| + want to set a breakpoint on the first PC of each range. To filter
|
| + such cases, we use containing blocks -- for each PC found
|
| + above, we see if there are other PCs that are in the same
|
| + block. If yes, the other PCs are filtered out. */
|
| +
|
| + filter = XNEWVEC (int, intermediate_results.nelts);
|
| + make_cleanup (xfree, filter);
|
| + blocks = XNEWVEC (struct block *, intermediate_results.nelts);
|
| + make_cleanup (xfree, blocks);
|
| +
|
| + for (i = 0; i < intermediate_results.nelts; ++i)
|
| {
|
| - if (--depth == 0)
|
| - {
|
| - ++p;
|
| - break;
|
| - }
|
| + set_current_program_space (intermediate_results.sals[i].pspace);
|
| +
|
| + filter[i] = 1;
|
| + blocks[i] = block_for_pc_sect (intermediate_results.sals[i].pc,
|
| + intermediate_results.sals[i].section);
|
| }
|
| - ++p;
|
| +
|
| + for (i = 0; i < intermediate_results.nelts; ++i)
|
| + {
|
| + if (blocks[i] != NULL)
|
| + for (j = i + 1; j < intermediate_results.nelts; ++j)
|
| + {
|
| + if (blocks[j] == blocks[i])
|
| + {
|
| + filter[j] = 0;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + for (i = 0; i < intermediate_results.nelts; ++i)
|
| + if (filter[i])
|
| + {
|
| + struct symbol *sym = (blocks[i]
|
| + ? block_containing_function (blocks[i])
|
| + : NULL);
|
| +
|
| + if (self->funfirstline)
|
| + skip_prologue_sal (&intermediate_results.sals[i]);
|
| + /* Make sure the line matches the request, not what was
|
| + found. */
|
| + intermediate_results.sals[i].line = val.line;
|
| + add_sal_to_sals (self, &values, &intermediate_results.sals[i],
|
| + sym ? SYMBOL_NATURAL_NAME (sym) : NULL);
|
| + }
|
| +
|
| + do_cleanups (cleanup);
|
| }
|
|
|
| - return p;
|
| + if (values.nelts == 0)
|
| + {
|
| + if (ls->source_filename)
|
| + throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
|
| + val.line, ls->source_filename);
|
| + else
|
| + throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
|
| + val.line);
|
| + }
|
| +
|
| + return values;
|
| }
|
|
|
| -/* Keep important information used when looking up a name. This includes
|
| - template parameters, overload information, and important keywords, including
|
| - the possible Java trailing type. */
|
| +/* Create and return SALs from the linespec LS. */
|
|
|
| -static char *
|
| -keep_name_info (char *p, int on_boundary)
|
| +static struct symtabs_and_lines
|
| +convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
|
| {
|
| - const char *quotes = get_gdb_completer_quote_characters ();
|
| - char *saved_p = p;
|
| - int nest = 0;
|
| + struct symtabs_and_lines sals = {NULL, 0};
|
|
|
| - while (*p)
|
| + if (ls->expression != NULL)
|
| {
|
| - if (strchr (quotes, *p))
|
| - break;
|
| -
|
| - if (*p == ',' && !nest)
|
| - break;
|
| + /* We have an expression. No other attribute is allowed. */
|
| + sals.sals = XMALLOC (struct symtab_and_line);
|
| + sals.nelts = 1;
|
| + sals.sals[0] = find_pc_line (ls->expr_pc, 0);
|
| + sals.sals[0].pc = ls->expr_pc;
|
| + sals.sals[0].section = find_pc_overlay (ls->expr_pc);
|
| + sals.sals[0].explicit_pc = 1;
|
| + }
|
| + else if (ls->labels.label_symbols != NULL)
|
| + {
|
| + /* We have just a bunch of functions/methods or labels. */
|
| + int i;
|
| + struct symtab_and_line sal;
|
| + struct symbol *sym;
|
|
|
| - if (on_boundary && !nest)
|
| + for (i = 0; VEC_iterate (symbolp, ls->labels.label_symbols, i, sym); ++i)
|
| {
|
| - const char *const words[] = { "if", "thread", "task" };
|
| - int wordi;
|
| -
|
| - for (wordi = 0; wordi < ARRAY_SIZE (words); wordi++)
|
| - if (strncmp (p, words[wordi], strlen (words[wordi])) == 0
|
| - && is_linespec_boundary (p[strlen (words[wordi])]))
|
| - break;
|
| - if (wordi < ARRAY_SIZE (words))
|
| - break;
|
| + if (symbol_to_sal (&sal, state->funfirstline, sym))
|
| + add_sal_to_sals (state, &sals, &sal,
|
| + SYMBOL_NATURAL_NAME (sym));
|
| }
|
| + }
|
| + else if (ls->function_symbols != NULL || ls->minimal_symbols != NULL)
|
| + {
|
| + /* We have just a bunch of functions and/or methods. */
|
| + int i;
|
| + struct symtab_and_line sal;
|
| + struct symbol *sym;
|
| + minsym_and_objfile_d *elem;
|
| + struct program_space *pspace;
|
|
|
| - if (*p == '(' || *p == '<' || *p == '[')
|
| - nest++;
|
| - else if ((*p == ')' || *p == '>' || *p == ']') && nest > 0)
|
| - nest--;
|
| + if (ls->function_symbols != NULL)
|
| + {
|
| + /* Sort symbols so that symbols with the same program space are next
|
| + to each other. */
|
| + qsort (VEC_address (symbolp, ls->function_symbols),
|
| + VEC_length (symbolp, ls->function_symbols),
|
| + sizeof (symbolp), compare_symbols);
|
|
|
| - p++;
|
| + for (i = 0; VEC_iterate (symbolp, ls->function_symbols, i, sym); ++i)
|
| + {
|
| + pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
|
| + set_current_program_space (pspace);
|
| + if (symbol_to_sal (&sal, state->funfirstline, sym)
|
| + && maybe_add_address (state->addr_set, pspace, sal.pc))
|
| + add_sal_to_sals (state, &sals, &sal, SYMBOL_NATURAL_NAME (sym));
|
| + }
|
| + }
|
|
|
| - /* The ',' check could fail on "operator ,". */
|
| - p += cp_validate_operator (p);
|
| + if (ls->minimal_symbols != NULL)
|
| + {
|
| + /* Sort minimal symbols by program space, too. */
|
| + qsort (VEC_address (minsym_and_objfile_d, ls->minimal_symbols),
|
| + VEC_length (minsym_and_objfile_d, ls->minimal_symbols),
|
| + sizeof (minsym_and_objfile_d), compare_msymbols);
|
| +
|
| + for (i = 0;
|
| + VEC_iterate (minsym_and_objfile_d, ls->minimal_symbols, i, elem);
|
| + ++i)
|
| + {
|
| + pspace = elem->objfile->pspace;
|
| + set_current_program_space (pspace);
|
| + minsym_found (state, elem->objfile, elem->minsym, &sals);
|
| + }
|
| + }
|
| + }
|
| + else if (ls->line_offset.sign != LINE_OFFSET_UNKNOWN)
|
| + {
|
| + /* Only an offset was specified. */
|
| + sals = create_sals_line_offset (state, ls);
|
|
|
| - on_boundary = is_linespec_boundary (p[-1]);
|
| + /* Make sure we have a filename for canonicalization. */
|
| + if (ls->source_filename == NULL)
|
| + ls->source_filename = xstrdup (state->default_symtab->filename);
|
| + }
|
| + else
|
| + {
|
| + /* We haven't found any results... */
|
| + return sals;
|
| }
|
|
|
| - while (p > saved_p && is_linespec_boundary (p[-1]))
|
| - p--;
|
| + canonicalize_linespec (state, ls);
|
|
|
| - return p;
|
| -}
|
| + if (sals.nelts > 0 && state->canonical != NULL)
|
| + state->canonical->pre_expanded = 1;
|
|
|
| -
|
| -/* The parser of linespec itself. */
|
| + return sals;
|
| +}
|
|
|
| -/* Parse a string that specifies a line number.
|
| +/* Parse a string that specifies a linespec.
|
| Pass the address of a char * variable; that variable will be
|
| advanced over the characters actually parsed.
|
|
|
| - The string can be:
|
| + The basic grammar of linespecs:
|
| +
|
| + linespec -> expr_spec | var_spec | basic_spec
|
| + expr_spec -> '*' STRING
|
| + var_spec -> '$' (STRING | NUMBER)
|
|
|
| - LINENUM -- that line number in current file. PC returned is 0.
|
| - FILE:LINENUM -- that line in that file. PC returned is 0.
|
| - FUNCTION -- line number of openbrace of that function.
|
| - PC returned is the start of the function.
|
| - LABEL -- a label in the current scope
|
| - VARIABLE -- line number of definition of that variable.
|
| - PC returned is 0.
|
| - FILE:FUNCTION -- likewise, but prefer functions in that file.
|
| - *EXPR -- line in which address EXPR appears.
|
| + basic_spec -> file_offset_spec | function_spec | label_spec
|
| + file_offset_spec -> opt_file_spec offset_spec
|
| + function_spec -> opt_file_spec function_name_spec opt_label_spec
|
| + label_spec -> label_name_spec
|
|
|
| - This may all be followed by an "if EXPR", which we ignore.
|
| + opt_file_spec -> "" | file_name_spec ':'
|
| + opt_label_spec -> "" | ':' label_name_spec
|
|
|
| - FUNCTION may be an undebuggable function found in minimal symbol table.
|
| + file_name_spec -> STRING
|
| + function_name_spec -> STRING
|
| + label_name_spec -> STRING
|
| + function_name_spec -> STRING
|
| + offset_spec -> NUMBER
|
| + -> '+' NUMBER
|
| + -> '-' NUMBER
|
| +
|
| + This may all be followed by several keywords such as "if EXPR",
|
| + which we ignore.
|
| +
|
| + A comma will terminate parsing.
|
| +
|
| + The function may be an undebuggable function found in minimal symbol table.
|
|
|
| If the argument FUNFIRSTLINE is nonzero, we want the first line
|
| of real code inside a function when a function is specified, and it is
|
| @@ -825,319 +2000,215 @@ keep_name_info (char *p, int on_boundary)
|
| if no file is validly specified. Callers must check that.
|
| Also, the line number returned may be invalid. */
|
|
|
| -/* We allow single quotes in various places. This is a hideous
|
| - kludge, which exists because the completer can't yet deal with the
|
| - lack of single quotes. FIXME: write a linespec_completer which we
|
| - can use as appropriate instead of make_symbol_completion_list. */
|
| +/* Parse the linespec in ARGPTR. */
|
|
|
| -struct symtabs_and_lines
|
| -decode_line_internal (struct linespec_state *self, char **argptr)
|
| +static struct symtabs_and_lines
|
| +parse_linespec (linespec_parser *parser, char **argptr)
|
| {
|
| - char *p;
|
| - char *q;
|
| -
|
| - char *copy;
|
| - /* This says whether or not something in *ARGPTR is quoted with
|
| - completer_quotes (i.e. with single quotes). */
|
| - int is_quoted;
|
| - /* Is *ARGPTR enclosed in double quotes? */
|
| - int is_quote_enclosed;
|
| - int is_objc_method = 0;
|
| - char *saved_arg = *argptr;
|
| - /* If IS_QUOTED, the end of the quoted bit. */
|
| - char *end_quote = NULL;
|
| - /* Is *ARGPTR enclosed in single quotes? */
|
| - int is_squote_enclosed = 0;
|
| - /* The "first half" of the linespec. */
|
| - char *first_half;
|
| -
|
| - /* If we are parsing `function:label', this holds the symbols
|
| - matching the function name. */
|
| - VEC (symbolp) *function_symbols = NULL;
|
| - /* If FUNCTION_SYMBOLS is not NULL, then this is the exception that
|
| - was thrown when trying to parse a filename. */
|
| + linespec_token token;
|
| + struct symtabs_and_lines values;
|
| volatile struct gdb_exception file_exception;
|
| + struct cleanup *cleanup;
|
|
|
| - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
|
| -
|
| - /* Defaults have defaults. */
|
| -
|
| - initialize_defaults (&self->default_symtab, &self->default_line);
|
| -
|
| - /* See if arg is *PC. */
|
| -
|
| - if (**argptr == '*')
|
| - {
|
| - do_cleanups (cleanup);
|
| - return decode_indirect (self, argptr);
|
| - }
|
| -
|
| - is_quoted = (strchr (get_gdb_completer_quote_characters (),
|
| - **argptr) != NULL);
|
| -
|
| - if (is_quoted)
|
| - {
|
| - end_quote = skip_quoted (*argptr);
|
| - if (*end_quote == '\0')
|
| - is_squote_enclosed = 1;
|
| - }
|
| -
|
| - /* Check to see if it's a multipart linespec (with colons or
|
| - periods). */
|
| -
|
| - /* Locate the end of the first half of the linespec.
|
| - After the call, for instance, if the argptr string is "foo.c:123"
|
| - p will point at "123". If there is only one part, like "foo", p
|
| - will point to "". If this is a C++ name, like "A::B::foo", p will
|
| - point to "::B::foo". Argptr is not changed by this call. */
|
| -
|
| - first_half = p = locate_first_half (argptr, &is_quote_enclosed);
|
| -
|
| - /* First things first: if ARGPTR starts with a filename, get its
|
| - symtab and strip the filename from ARGPTR. */
|
| - TRY_CATCH (file_exception, RETURN_MASK_ERROR)
|
| - {
|
| - self->file_symtabs = symtabs_from_filename (argptr, p, is_quote_enclosed,
|
| - &self->user_filename);
|
| - }
|
| -
|
| - if (VEC_empty (symtab_p, self->file_symtabs))
|
| - {
|
| - /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
|
| - VEC_safe_push (symtab_p, self->file_symtabs, NULL);
|
| - }
|
| -
|
| - if (file_exception.reason >= 0)
|
| + /* A special case to start. It has become quite popular for
|
| + IDEs to work around bugs in the previous parser by quoting
|
| + the entire linespec, so we attempt to deal with this nicely. */
|
| + parser->is_quote_enclosed = 0;
|
| + if (!is_ada_operator (*argptr)
|
| + && strchr (linespec_quote_characters, **argptr) != NULL)
|
| {
|
| - /* Check for single quotes on the non-filename part. */
|
| - is_quoted = (**argptr
|
| - && strchr (get_gdb_completer_quote_characters (),
|
| - **argptr) != NULL);
|
| - if (is_quoted)
|
| - end_quote = skip_quoted (*argptr);
|
| + const char *end;
|
|
|
| - /* Locate the next "half" of the linespec. */
|
| - first_half = p = locate_first_half (argptr, &is_quote_enclosed);
|
| + end = skip_quote_char (*argptr + 1, **argptr);
|
| + if (end != NULL && is_closing_quote_enclosed (end))
|
| + {
|
| + /* Here's the special case. Skip ARGPTR past the initial
|
| + quote. */
|
| + ++(*argptr);
|
| + parser->is_quote_enclosed = 1;
|
| + }
|
| }
|
|
|
| - /* Check if this is an Objective-C method (anything that starts with
|
| - a '+' or '-' and a '['). */
|
| - if (is_objc_method_format (p))
|
| - is_objc_method = 1;
|
| + /* A keyword at the start cannot be interpreted as such.
|
| + Consider "b thread thread 42". */
|
| + parser->keyword_ok = 0;
|
|
|
| - /* Check if the symbol could be an Objective-C selector. */
|
| + parser->lexer.saved_arg = *argptr;
|
| + parser->lexer.stream = argptr;
|
| + file_exception.reason = 0;
|
|
|
| - {
|
| - struct symtabs_and_lines values;
|
| + /* Initialize the default symtab and line offset. */
|
| + initialize_defaults (&PARSER_STATE (parser)->default_symtab,
|
| + &PARSER_STATE (parser)->default_line);
|
|
|
| - values = decode_objc (self, argptr);
|
| - if (values.sals != NULL)
|
| - {
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - }
|
| - }
|
| + /* Objective-C shortcut. */
|
| + values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), argptr);
|
| + if (values.sals != NULL)
|
| + return values;
|
| +
|
| + /* Start parsing. */
|
|
|
| - /* Does it look like there actually were two parts? */
|
| + /* Get the first token. */
|
| + token = linespec_lexer_lex_one (parser);
|
|
|
| - if (p[0] == ':' || p[0] == '.')
|
| + /* It must be either LSTOKEN_STRING or LSTOKEN_NUMBER. */
|
| + if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '*')
|
| {
|
| - /* Is it a C++ or Java compound data structure?
|
| - The check on p[1] == ':' is capturing the case of "::",
|
| - since p[0]==':' was checked above.
|
| - Note that the call to decode_compound does everything
|
| - for us, including the lookup on the symbol table, so we
|
| - can return now. */
|
| -
|
| - if (p[0] == '.' || p[1] == ':')
|
| - {
|
| - struct symtabs_and_lines values;
|
| - volatile struct gdb_exception ex;
|
| - char *saved_argptr = *argptr;
|
| + char *expr, *copy;
|
|
|
| - if (is_quote_enclosed)
|
| - ++saved_arg;
|
| + /* User specified an expression, *EXPR. */
|
| + copy = expr = copy_token_string (token);
|
| + cleanup = make_cleanup (xfree, expr);
|
| + PARSER_RESULT (parser)->expr_pc = linespec_expression_to_pc (©);
|
| + discard_cleanups (cleanup);
|
| + PARSER_RESULT (parser)->expression = expr;
|
|
|
| - /* Initialize it just to avoid a GCC false warning. */
|
| - memset (&values, 0, sizeof (values));
|
| + /* This is a little hacky/tricky. If linespec_expression_to_pc
|
| + did not evaluate the entire token, then we must find the
|
| + string COPY inside the original token buffer. */
|
| + if (*copy != '\0')
|
| + {
|
| + PARSER_STREAM (parser) = strstr (parser->lexer.saved_arg, copy);
|
| + gdb_assert (PARSER_STREAM (parser) != NULL);
|
| + }
|
|
|
| - TRY_CATCH (ex, RETURN_MASK_ERROR)
|
| - {
|
| - values = decode_compound (self, argptr, saved_arg, p);
|
| - }
|
| - if ((is_quoted || is_squote_enclosed) && **argptr == '\'')
|
| - *argptr = *argptr + 1;
|
| + /* Consume the token. */
|
| + linespec_lexer_consume_token (parser);
|
|
|
| - if (ex.reason >= 0)
|
| - {
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - }
|
| + goto convert_to_sals;
|
| + }
|
| + else if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '$')
|
| + {
|
| + char *var;
|
|
|
| - if (ex.error != NOT_FOUND_ERROR)
|
| - throw_exception (ex);
|
| + /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
|
| + VEC_safe_push (symtab_p, PARSER_RESULT (parser)->file_symtabs, NULL);
|
|
|
| - *argptr = saved_argptr;
|
| - }
|
| - else
|
| - {
|
| - /* If there was an exception looking up a specified filename earlier,
|
| - then check whether we were really given `function:label'. */
|
| - if (file_exception.reason < 0)
|
| - {
|
| - function_symbols = find_function_symbols (argptr, p,
|
| - is_quote_enclosed,
|
| - &self->user_function);
|
| + /* User specified a convenience variable or history value. */
|
| + var = copy_token_string (token);
|
| + cleanup = make_cleanup (xfree, var);
|
| + PARSER_RESULT (parser)->line_offset
|
| + = linespec_parse_variable (PARSER_STATE (parser), var);
|
|
|
| - /* If we did not find a function, re-throw the original
|
| - exception. */
|
| - if (!function_symbols)
|
| - throw_exception (file_exception);
|
| + /* 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)
|
| + {
|
| + discard_cleanups (cleanup);
|
|
|
| - make_cleanup (VEC_cleanup (symbolp), &function_symbols);
|
| - }
|
| + /* Consume this token. */
|
| + linespec_lexer_consume_token (parser);
|
|
|
| - /* Check for single quotes on the non-filename part. */
|
| - if (!is_quoted)
|
| - {
|
| - is_quoted = (**argptr
|
| - && strchr (get_gdb_completer_quote_characters (),
|
| - **argptr) != NULL);
|
| - if (is_quoted)
|
| - end_quote = skip_quoted (*argptr);
|
| - }
|
| + goto convert_to_sals;
|
| }
|
| +
|
| + do_cleanups (cleanup);
|
| }
|
| + else if (token.type != LSTOKEN_STRING && token.type != LSTOKEN_NUMBER)
|
| + unexpected_linespec_error (parser);
|
|
|
| - /* self->file_symtabs holds the specified file symtabs, or 0 if no file
|
| - specified.
|
| - If we are parsing `function:symbol', then FUNCTION_SYMBOLS holds the
|
| - functions before the `:'.
|
| - arg no longer contains the file name. */
|
| + /* Now we can recognize keywords. */
|
| + parser->keyword_ok = 1;
|
|
|
| - /* If the filename was quoted, we must re-check the quotation. */
|
| + /* Shortcut: If the next token is not LSTOKEN_COLON, we know that
|
| + this token cannot represent a filename. */
|
| + token = linespec_lexer_peek_token (parser);
|
|
|
| - if (end_quote == first_half && *end_quote!= '\0')
|
| + if (token.type == LSTOKEN_COLON)
|
| {
|
| - is_quoted = (**argptr
|
| - && strchr (get_gdb_completer_quote_characters (),
|
| - **argptr) != NULL);
|
| - if (is_quoted)
|
| - end_quote = skip_quoted (*argptr);
|
| - }
|
| + char *user_filename;
|
|
|
| - /* Check whether arg is all digits (and sign). */
|
| + /* Get the current token again and extract the filename. */
|
| + token = linespec_lexer_lex_one (parser);
|
| + user_filename = copy_token_string (token);
|
|
|
| - q = *argptr;
|
| - if (*q == '-' || *q == '+')
|
| - q++;
|
| - while (*q >= '0' && *q <= '9')
|
| - q++;
|
| + /* Check if the input is a filename. */
|
| + TRY_CATCH (file_exception, RETURN_MASK_ERROR)
|
| + {
|
| + PARSER_RESULT (parser)->file_symtabs
|
| + = symtabs_from_filename (user_filename);
|
| + }
|
|
|
| - if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',')
|
| - && function_symbols == NULL)
|
| - {
|
| - struct symtabs_and_lines values;
|
| + if (file_exception.reason >= 0)
|
| + {
|
| + /* Symtabs were found for the file. Record the filename. */
|
| + PARSER_RESULT (parser)->source_filename = user_filename;
|
|
|
| - /* We found a token consisting of all digits -- at least one digit. */
|
| - values = decode_all_digits (self, argptr, q);
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - }
|
| + /* Get the next token. */
|
| + token = linespec_lexer_consume_token (parser);
|
|
|
| - /* Arg token is not digits => try it as a variable name
|
| - Find the next token (everything up to end or next whitespace). */
|
| + /* This is LSTOKEN_COLON; consume it. */
|
| + linespec_lexer_consume_token (parser);
|
| + }
|
| + else
|
| + {
|
| + /* No symtabs found -- discard user_filename. */
|
| + xfree (user_filename);
|
|
|
| - if (**argptr == '$') /* May be a convenience variable. */
|
| - /* One or two $ chars possible. */
|
| - p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1));
|
| - else if (is_quoted || is_squote_enclosed)
|
| - {
|
| - p = end_quote;
|
| - if (p[-1] != '\'')
|
| - error (_("Unmatched single quote."));
|
| + /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
|
| + VEC_safe_push (symtab_p, PARSER_RESULT (parser)->file_symtabs, NULL);
|
| + }
|
| }
|
| - else if (is_objc_method)
|
| + /* If the next token is not EOI, KEYWORD, or COMMA, issue an error. */
|
| + else if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD
|
| + && token.type != LSTOKEN_COMMA)
|
| {
|
| - /* allow word separators in method names for Obj-C. */
|
| - p = skip_quoted_chars (*argptr, NULL, "");
|
| + /* TOKEN is the _next_ token, not the one currently in the parser.
|
| + Consuming the token will give the correct error message. */
|
| + linespec_lexer_consume_token (parser);
|
| + unexpected_linespec_error (parser);
|
| }
|
| else
|
| {
|
| - p = skip_quoted (*argptr);
|
| - }
|
| -
|
| - /* Keep any important naming information. */
|
| - p = keep_name_info (p, p == saved_arg || is_linespec_boundary (p[-1]));
|
| -
|
| - copy = (char *) alloca (p - *argptr + 1);
|
| - memcpy (copy, *argptr, p - *argptr);
|
| - copy[p - *argptr] = '\0';
|
| - if (p != *argptr
|
| - && copy[0]
|
| - && copy[0] == copy[p - *argptr - 1]
|
| - && strchr (get_gdb_completer_quote_characters (), copy[0]) != NULL)
|
| - {
|
| - copy[p - *argptr - 1] = '\0';
|
| - copy++;
|
| + /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB. */
|
| + VEC_safe_push (symtab_p, PARSER_RESULT (parser)->file_symtabs, NULL);
|
| }
|
| - else if (is_quoted || is_squote_enclosed)
|
| - copy[p - *argptr - 1] = '\0';
|
| -
|
| - *argptr = skip_spaces (p);
|
|
|
| - /* If it starts with $: may be a legitimate variable or routine name
|
| - (e.g. HP-UX millicode routines such as $$dyncall), or it may
|
| - be history value, or it may be a convenience variable. */
|
| + /* Parse the rest of the linespec. */
|
| + linespec_parse_basic (parser);
|
|
|
| - if (*copy == '$' && function_symbols == NULL)
|
| + if (PARSER_RESULT (parser)->function_symbols == NULL
|
| + && PARSER_RESULT (parser)->labels.label_symbols == NULL
|
| + && PARSER_RESULT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
|
| + && PARSER_RESULT (parser)->minimal_symbols == NULL)
|
| {
|
| - struct symtabs_and_lines values;
|
| -
|
| - values = decode_dollar (self, copy);
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - }
|
| + /* The linespec didn't parse. Re-throw the file exception if
|
| + there was one. */
|
| + if (file_exception.reason < 0)
|
| + throw_exception (file_exception);
|
|
|
| - /* Try the token as a label, but only if no file was specified,
|
| - because we can only really find labels in the current scope. */
|
| -
|
| - if (VEC_length (symtab_p, self->file_symtabs) == 1
|
| - && VEC_index (symtab_p, self->file_symtabs, 0) == NULL)
|
| - {
|
| - struct symtabs_and_lines label_result;
|
| - if (decode_label (self, function_symbols, copy, &label_result))
|
| - {
|
| - do_cleanups (cleanup);
|
| - return label_result;
|
| - }
|
| + /* Otherwise, the symbol is not found. */
|
| + symbol_not_found_error (PARSER_RESULT (parser)->function_name,
|
| + PARSER_RESULT (parser)->source_filename);
|
| }
|
|
|
| - if (function_symbols)
|
| - throw_exception (file_exception);
|
| + convert_to_sals:
|
|
|
| - /* Look up that token as a variable.
|
| - If file specified, use that file's per-file block to start with. */
|
| + /* Get the last token and record how much of the input was parsed,
|
| + if necessary. */
|
| + token = linespec_lexer_lex_one (parser);
|
| + if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD)
|
| + PARSER_STREAM (parser) = LS_TOKEN_STOKEN (token).ptr;
|
|
|
| - {
|
| - struct symtabs_and_lines values;
|
| + /* Convert the data in PARSER_RESULT to SALs. */
|
| + values = convert_linespec_to_sals (PARSER_STATE (parser),
|
| + PARSER_RESULT (parser));
|
|
|
| - values = decode_variable (self, copy);
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - }
|
| + return values;
|
| }
|
|
|
| +
|
| /* A constructor for linespec_state. */
|
|
|
| static void
|
| linespec_state_constructor (struct linespec_state *self,
|
| - int flags,
|
| + int flags, const struct language_defn *language,
|
| struct symtab *default_symtab,
|
| int default_line,
|
| struct linespec_result *canonical)
|
| {
|
| memset (self, 0, sizeof (*self));
|
| + self->language = language;
|
| self->funfirstline = (flags & DECODE_LINE_FUNFIRSTLINE) ? 1 : 0;
|
| self->list_mode = (flags & DECODE_LINE_LIST_MODE) ? 1 : 0;
|
| self->default_symtab = default_symtab;
|
| @@ -1148,19 +2219,64 @@ linespec_state_constructor (struct linespec_state *self,
|
| xfree, xcalloc, xfree);
|
| }
|
|
|
| +/* Initialize a new linespec parser. */
|
| +
|
| +static void
|
| +linespec_parser_new (linespec_parser *parser,
|
| + int flags, const struct language_defn *language,
|
| + struct symtab *default_symtab,
|
| + int default_line,
|
| + struct linespec_result *canonical)
|
| +{
|
| + parser->lexer.current.type = LSTOKEN_CONSUMED;
|
| + memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
|
| + PARSER_RESULT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
|
| + linespec_state_constructor (PARSER_STATE (parser), flags, language,
|
| + default_symtab, default_line, canonical);
|
| +}
|
| +
|
| /* A destructor for linespec_state. */
|
|
|
| static void
|
| -linespec_state_destructor (void *arg)
|
| +linespec_state_destructor (struct linespec_state *self)
|
| {
|
| - struct linespec_state *self = arg;
|
| -
|
| - xfree (self->user_filename);
|
| - xfree (self->user_function);
|
| - VEC_free (symtab_p, self->file_symtabs);
|
| htab_delete (self->addr_set);
|
| }
|
|
|
| +/* Delete a linespec parser. */
|
| +
|
| +static void
|
| +linespec_parser_delete (void *arg)
|
| +{
|
| + linespec_parser *parser = (linespec_parser *) arg;
|
| +
|
| + if (PARSER_RESULT (parser)->expression)
|
| + xfree (PARSER_RESULT (parser)->expression);
|
| + if (PARSER_RESULT (parser)->source_filename)
|
| + xfree (PARSER_RESULT (parser)->source_filename);
|
| + if (PARSER_RESULT (parser)->label_name)
|
| + xfree (PARSER_RESULT (parser)->label_name);
|
| + if (PARSER_RESULT (parser)->function_name)
|
| + xfree (PARSER_RESULT (parser)->function_name);
|
| +
|
| + if (PARSER_RESULT (parser)->file_symtabs != NULL)
|
| + VEC_free (symtab_p, PARSER_RESULT (parser)->file_symtabs);
|
| +
|
| + if (PARSER_RESULT (parser)->function_symbols != NULL)
|
| + VEC_free (symbolp, PARSER_RESULT (parser)->function_symbols);
|
| +
|
| + if (PARSER_RESULT (parser)->minimal_symbols != NULL)
|
| + VEC_free (minsym_and_objfile_d, PARSER_RESULT (parser)->minimal_symbols);
|
| +
|
| + if (PARSER_RESULT (parser)->labels.label_symbols != NULL)
|
| + VEC_free (symbolp, PARSER_RESULT (parser)->labels.label_symbols);
|
| +
|
| + if (PARSER_RESULT (parser)->labels.function_symbols != NULL)
|
| + VEC_free (symbolp, PARSER_RESULT (parser)->labels.function_symbols);
|
| +
|
| + linespec_state_destructor (PARSER_STATE (parser));
|
| +}
|
| +
|
| /* See linespec.h. */
|
|
|
| void
|
| @@ -1171,10 +2287,11 @@ decode_line_full (char **argptr, int flags,
|
| const char *filter)
|
| {
|
| struct symtabs_and_lines result;
|
| - struct linespec_state state;
|
| struct cleanup *cleanups;
|
| char *arg_start = *argptr;
|
| VEC (const_char_ptr) *filters = NULL;
|
| + linespec_parser parser;
|
| + struct linespec_state *state;
|
|
|
| gdb_assert (canonical != NULL);
|
| /* The filter only makes sense for 'all'. */
|
| @@ -1185,12 +2302,13 @@ decode_line_full (char **argptr, int flags,
|
| || select_mode == multiple_symbols_cancel);
|
| gdb_assert ((flags & DECODE_LINE_LIST_MODE) == 0);
|
|
|
| - linespec_state_constructor (&state, flags,
|
| - default_symtab, default_line, canonical);
|
| - cleanups = make_cleanup (linespec_state_destructor, &state);
|
| + linespec_parser_new (&parser, flags, current_language, default_symtab,
|
| + default_line, canonical);
|
| + cleanups = make_cleanup (linespec_parser_delete, &parser);
|
| save_current_program_space ();
|
|
|
| - result = decode_line_internal (&state, argptr);
|
| + result = parse_linespec (&parser, argptr);
|
| + state = PARSER_STATE (&parser);
|
|
|
| gdb_assert (result.nelts == 1 || canonical->pre_expanded);
|
| gdb_assert (canonical->addr_string != NULL);
|
| @@ -1201,15 +2319,15 @@ decode_line_full (char **argptr, int flags,
|
| {
|
| int i;
|
|
|
| - if (state.canonical_names == NULL)
|
| - state.canonical_names = xcalloc (result.nelts, sizeof (char *));
|
| - make_cleanup (xfree, state.canonical_names);
|
| + if (state->canonical_names == NULL)
|
| + state->canonical_names = xcalloc (result.nelts, sizeof (char *));
|
| + make_cleanup (xfree, state->canonical_names);
|
| for (i = 0; i < result.nelts; ++i)
|
| {
|
| - if (state.canonical_names[i] == NULL)
|
| - state.canonical_names[i] = savestring (arg_start,
|
| - *argptr - arg_start);
|
| - make_cleanup (xfree, state.canonical_names[i]);
|
| + if (state->canonical_names[i] == NULL)
|
| + state->canonical_names[i] = savestring (arg_start,
|
| + *argptr - arg_start);
|
| + make_cleanup (xfree, state->canonical_names[i]);
|
| }
|
| }
|
|
|
| @@ -1227,36 +2345,84 @@ decode_line_full (char **argptr, int flags,
|
| {
|
| make_cleanup (VEC_cleanup (const_char_ptr), &filters);
|
| VEC_safe_push (const_char_ptr, filters, filter);
|
| - filter_results (&state, &result, filters);
|
| + filter_results (state, &result, filters);
|
| }
|
| else
|
| - convert_results_to_lsals (&state, &result);
|
| + convert_results_to_lsals (state, &result);
|
| }
|
| else
|
| - decode_line_2 (&state, &result, select_mode);
|
| + decode_line_2 (state, &result, select_mode);
|
|
|
| do_cleanups (cleanups);
|
| }
|
|
|
| +/* See linespec.h. */
|
| +
|
| struct symtabs_and_lines
|
| decode_line_1 (char **argptr, int flags,
|
| struct symtab *default_symtab,
|
| int default_line)
|
| {
|
| struct symtabs_and_lines result;
|
| - struct linespec_state state;
|
| + linespec_parser parser;
|
| struct cleanup *cleanups;
|
|
|
| - linespec_state_constructor (&state, flags,
|
| - default_symtab, default_line, NULL);
|
| - cleanups = make_cleanup (linespec_state_destructor, &state);
|
| + linespec_parser_new (&parser, flags, current_language, default_symtab,
|
| + default_line, NULL);
|
| + cleanups = make_cleanup (linespec_parser_delete, &parser);
|
| save_current_program_space ();
|
|
|
| - result = decode_line_internal (&state, argptr);
|
| + result = parse_linespec (&parser, argptr);
|
| +
|
| do_cleanups (cleanups);
|
| return result;
|
| }
|
|
|
| +/* See linespec.h. */
|
| +
|
| +struct symtabs_and_lines
|
| +decode_line_with_current_source (char *string, int flags)
|
| +{
|
| + struct symtabs_and_lines sals;
|
| + struct symtab_and_line cursal;
|
| +
|
| + if (string == 0)
|
| + error (_("Empty line specification."));
|
| +
|
| + /* We use whatever is set as the current source line. We do not try
|
| + and get a default source symtab+line or it will recursively call us! */
|
| + cursal = get_current_source_symtab_and_line ();
|
| +
|
| + sals = decode_line_1 (&string, flags,
|
| + cursal.symtab, cursal.line);
|
| +
|
| + if (*string)
|
| + error (_("Junk at end of line specification: %s"), string);
|
| + return sals;
|
| +}
|
| +
|
| +/* See linespec.h. */
|
| +
|
| +struct symtabs_and_lines
|
| +decode_line_with_last_displayed (char *string, int flags)
|
| +{
|
| + struct symtabs_and_lines sals;
|
| +
|
| + if (string == 0)
|
| + error (_("Empty line specification."));
|
| +
|
| + if (last_displayed_sal_is_valid ())
|
| + sals = decode_line_1 (&string, flags,
|
| + get_last_displayed_symtab (),
|
| + get_last_displayed_line ());
|
| + else
|
| + sals = decode_line_1 (&string, flags, (struct symtab *) NULL, 0);
|
| +
|
| + if (*string)
|
| + error (_("Junk at end of line specification: %s"), string);
|
| + return sals;
|
| +}
|
| +
|
|
|
|
|
| /* First, some functions to initialize stuff at the beggining of the
|
| @@ -1280,160 +2446,20 @@ initialize_defaults (struct symtab **default_symtab, int *default_line)
|
|
|
|
|
|
|
| -/* Decode arg of the form *PC. */
|
| +/* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
|
| + advancing EXP_PTR past any parsed text. */
|
|
|
| -static struct symtabs_and_lines
|
| -decode_indirect (struct linespec_state *self, char **argptr)
|
| +static CORE_ADDR
|
| +linespec_expression_to_pc (char **exp_ptr)
|
| {
|
| - struct symtabs_and_lines values;
|
| - CORE_ADDR pc;
|
| - char *initial = *argptr;
|
| -
|
| if (current_program_space->executing_startup)
|
| /* The error message doesn't really matter, because this case
|
| should only hit during breakpoint reset. */
|
| throw_error (NOT_FOUND_ERROR, _("cannot evaluate expressions while "
|
| "program space is in startup"));
|
|
|
| - (*argptr)++;
|
| - pc = value_as_address (parse_to_comma_and_eval (argptr));
|
| -
|
| - values.sals = (struct symtab_and_line *)
|
| - xmalloc (sizeof (struct symtab_and_line));
|
| -
|
| - values.nelts = 1;
|
| - values.sals[0] = find_pc_line (pc, 0);
|
| - values.sals[0].pc = pc;
|
| - values.sals[0].section = find_pc_overlay (pc);
|
| - values.sals[0].explicit_pc = 1;
|
| -
|
| - if (self->canonical)
|
| - self->canonical->addr_string = savestring (initial, *argptr - initial);
|
| -
|
| - return values;
|
| -}
|
| -
|
| -
|
| -
|
| -/* Locate the first half of the linespec, ending in a colon, period,
|
| - or whitespace. (More or less.) Also, check to see if *ARGPTR is
|
| - enclosed in double quotes; if so, set is_quote_enclosed, advance
|
| - ARGPTR past that and zero out the trailing double quote.
|
| - If ARGPTR is just a simple name like "main", p will point to ""
|
| - at the end. */
|
| -
|
| -static char *
|
| -locate_first_half (char **argptr, int *is_quote_enclosed)
|
| -{
|
| - char *ii;
|
| - char *p, *p1;
|
| - int has_comma;
|
| -
|
| - /* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM
|
| - and we must isolate the first half. Outer layers will call again later
|
| - for the second half.
|
| -
|
| - Don't count commas that appear in argument lists of overloaded
|
| - functions, or in quoted strings. It's stupid to go to this much
|
| - trouble when the rest of the function is such an obvious roach hotel. */
|
| - ii = find_toplevel_char (*argptr, ',');
|
| - has_comma = (ii != 0);
|
| -
|
| - /* Temporarily zap out second half to not confuse the code below.
|
| - This is undone below. Do not change ii!! */
|
| - if (has_comma)
|
| - {
|
| - *ii = '\0';
|
| - }
|
| -
|
| - /* Maybe arg is FILE : LINENUM or FILE : FUNCTION. May also be
|
| - CLASS::MEMBER, or NAMESPACE::NAME. Look for ':', but ignore
|
| - inside of <>. */
|
| -
|
| - p = *argptr;
|
| - if (p[0] == '"')
|
| - {
|
| - *is_quote_enclosed = 1;
|
| - (*argptr)++;
|
| - p++;
|
| - }
|
| - else
|
| - {
|
| - *is_quote_enclosed = 0;
|
| - if (strchr (get_gdb_completer_quote_characters (), *p))
|
| - {
|
| - ++(*argptr);
|
| - ++p;
|
| - }
|
| - }
|
| -
|
| -
|
| - /* Check for a drive letter in the filename. This is done on all hosts
|
| - to capture cross-compilation environments. On Unixen, directory
|
| - separators are illegal in filenames, so if the user enters "e:/foo.c",
|
| - he is referring to a directory named "e:" and a source file named
|
| - "foo.c", and we still want to keep these two pieces together. */
|
| - if (isalpha (p[0]) && p[1] == ':' && IS_DIR_SEPARATOR (p[2]))
|
| - p += 3;
|
| -
|
| - for (; *p; p++)
|
| - {
|
| - if (p[0] == '<')
|
| - {
|
| - char *temp_end = find_template_name_end (p);
|
| -
|
| - if (!temp_end)
|
| - error (_("malformed template specification in command"));
|
| - p = temp_end;
|
| - }
|
| -
|
| - if (p[0] == '(')
|
| - p = find_method_overload_end (p);
|
| -
|
| - /* Check for a colon and a plus or minus and a [ (which
|
| - indicates an Objective-C method). */
|
| - if (is_objc_method_format (p))
|
| - {
|
| - break;
|
| - }
|
| - /* Check for the end of the first half of the linespec. End of
|
| - line, a tab, a colon or a space. But if enclosed in double
|
| - quotes we do not break on enclosed spaces. */
|
| - if (!*p
|
| - || p[0] == '\t'
|
| - || (p[0] == ':')
|
| - || ((p[0] == ' ') && !*is_quote_enclosed))
|
| - break;
|
| - if (p[0] == '.' && strchr (p, ':') == NULL)
|
| - {
|
| - /* Java qualified method. Find the *last* '.', since the
|
| - others are package qualifiers. Stop at any open parenthesis
|
| - which might provide overload information. */
|
| - for (p1 = p; *p1 && *p1 != '('; p1++)
|
| - {
|
| - if (*p1 == '.')
|
| - p = p1;
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - p = skip_spaces (p);
|
| -
|
| - /* If the closing double quote was left at the end, remove it. */
|
| - if (*is_quote_enclosed)
|
| - {
|
| - char *closing_quote = strchr (p - 1, '"');
|
| -
|
| - if (closing_quote && closing_quote[1] == '\0')
|
| - *closing_quote = '\0';
|
| - }
|
| -
|
| - /* Now that we've safely parsed the first half, put back ',' so
|
| - outer layers can see it. */
|
| - if (has_comma)
|
| - *ii = ',';
|
| -
|
| - return p;
|
| + (*exp_ptr)++;
|
| + return value_as_address (parse_to_comma_and_eval (exp_ptr));
|
| }
|
|
|
|
|
| @@ -1446,28 +2472,35 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
|
| the existing C++ code to let the user choose one. */
|
|
|
| static struct symtabs_and_lines
|
| -decode_objc (struct linespec_state *self, char **argptr)
|
| +decode_objc (struct linespec_state *self, linespec_p ls, char **argptr)
|
| {
|
| struct collect_info info;
|
| VEC (const_char_ptr) *symbol_names = NULL;
|
| + struct symtabs_and_lines values;
|
| char *new_argptr;
|
| struct cleanup *cleanup = make_cleanup (VEC_cleanup (const_char_ptr),
|
| &symbol_names);
|
|
|
| info.state = self;
|
| - info.result.sals = NULL;
|
| - info.result.nelts = 0;
|
| + info.file_symtabs = NULL;
|
| + VEC_safe_push (symtab_p, info.file_symtabs, NULL);
|
| + make_cleanup (VEC_cleanup (symtab_p), &info.file_symtabs);
|
| + info.result.symbols = NULL;
|
| + info.result.minimal_symbols = NULL;
|
| + values.nelts = 0;
|
| + values.sals = NULL;
|
|
|
| new_argptr = find_imps (*argptr, &symbol_names);
|
| if (VEC_empty (const_char_ptr, symbol_names))
|
| {
|
| do_cleanups (cleanup);
|
| - return info.result;
|
| + return values;
|
| }
|
|
|
| add_all_symbol_names_from_pspace (&info, NULL, symbol_names);
|
|
|
| - if (info.result.nelts > 0)
|
| + if (!VEC_empty (symbolp, info.result.symbols)
|
| + || !VEC_empty (minsym_and_objfile_d, info.result.minimal_symbols))
|
| {
|
| char *saved_arg;
|
|
|
| @@ -1475,12 +2508,16 @@ decode_objc (struct linespec_state *self, char **argptr)
|
| memcpy (saved_arg, *argptr, new_argptr - *argptr);
|
| saved_arg[new_argptr - *argptr] = '\0';
|
|
|
| + ls->function_symbols = info.result.symbols;
|
| + ls->minimal_symbols = info.result.minimal_symbols;
|
| + values = convert_linespec_to_sals (self, ls);
|
| +
|
| if (self->canonical)
|
| {
|
| self->canonical->pre_expanded = 1;
|
| - if (self->user_filename)
|
| + if (ls->source_filename)
|
| self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", self->user_filename, saved_arg);
|
| + = xstrprintf ("%s:%s", ls->source_filename, saved_arg);
|
| else
|
| self->canonical->addr_string = xstrdup (saved_arg);
|
| }
|
| @@ -1489,241 +2526,8 @@ decode_objc (struct linespec_state *self, char **argptr)
|
| *argptr = new_argptr;
|
|
|
| do_cleanups (cleanup);
|
| - return info.result;
|
| -}
|
| -
|
| -/* This handles C++ and Java compound data structures. P should point
|
| - at the first component separator, i.e. double-colon or period. As
|
| - an example, on entrance to this function we could have ARGPTR
|
| - pointing to "AAA::inA::fun" and P pointing to "::inA::fun". */
|
| -
|
| -static struct symtabs_and_lines
|
| -decode_compound (struct linespec_state *self,
|
| - char **argptr, char *the_real_saved_arg, char *p)
|
| -{
|
| - struct symtabs_and_lines values;
|
| - char *p2;
|
| - char *saved_arg2 = *argptr;
|
| - char *temp_end;
|
| - struct symbol *sym;
|
| - char *copy;
|
| - VEC (symbolp) *sym_classes;
|
| - char *saved_arg, *class_name;
|
| - struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
|
| -
|
| - /* If the user specified any completer quote characters in the input,
|
| - strip them. They are superfluous. */
|
| - saved_arg = alloca (strlen (the_real_saved_arg) + 1);
|
| - {
|
| - char *dst = saved_arg;
|
| - char *src = the_real_saved_arg;
|
| - char *quotes = get_gdb_completer_quote_characters ();
|
| - while (*src != '\0')
|
| - {
|
| - if (strchr (quotes, *src) == NULL)
|
| - *dst++ = *src;
|
| - ++src;
|
| - }
|
| - *dst = '\0';
|
| - }
|
| -
|
| - /* First check for "global" namespace specification, of the form
|
| - "::foo". If found, skip over the colons and jump to normal
|
| - symbol processing. I.e. the whole line specification starts with
|
| - "::" (note the condition that *argptr == p). */
|
| - if (p[0] == ':'
|
| - && ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
|
| - saved_arg2 += 2;
|
| -
|
| - /* Given our example "AAA::inA::fun", we have two cases to consider:
|
| -
|
| - 1) AAA::inA is the name of a class. In that case, presumably it
|
| - has a method called "fun"; we then look up that method using
|
| - find_method.
|
| -
|
| - 2) AAA::inA isn't the name of a class. In that case, either the
|
| - user made a typo, AAA::inA is the name of a namespace, or it is
|
| - the name of a minimal symbol.
|
| - In this case we just delegate to decode_variable.
|
| -
|
| - Thus, our first task is to find everything before the last set of
|
| - double-colons and figure out if it's the name of a class. So we
|
| - first loop through all of the double-colons. */
|
| -
|
| - p2 = p; /* Save for restart. */
|
| -
|
| - /* This is very messy. Following the example above we have now the
|
| - following pointers:
|
| - p -> "::inA::fun"
|
| - argptr -> "AAA::inA::fun
|
| - saved_arg -> "AAA::inA::fun
|
| - saved_arg2 -> "AAA::inA::fun
|
| - p2 -> "::inA::fun". */
|
| -
|
| - /* In the loop below, with these strings, we'll make 2 passes, each
|
| - is marked in comments. */
|
| -
|
| - while (1)
|
| - {
|
| - static char *break_characters = " \t(";
|
| -
|
| - /* Move pointer up to next possible class/namespace token. */
|
| -
|
| - p = p2 + 1; /* Restart with old value +1. */
|
| -
|
| - /* PASS1: at this point p2->"::inA::fun", so p->":inA::fun",
|
| - i.e. if there is a double-colon, p will now point to the
|
| - second colon. */
|
| - /* PASS2: p2->"::fun", p->":fun" */
|
|
|
| - /* Move pointer ahead to next double-colon. */
|
| - while (*p
|
| - && strchr (break_characters, *p) == NULL
|
| - && strchr (get_gdb_completer_quote_characters (), *p) == NULL)
|
| - {
|
| - if (current_language->la_language == language_cplus)
|
| - p += cp_validate_operator (p);
|
| -
|
| - if (p[0] == '<')
|
| - {
|
| - temp_end = find_template_name_end (p);
|
| - if (!temp_end)
|
| - error (_("malformed template specification in command"));
|
| - p = temp_end;
|
| - }
|
| - /* Note that, since, at the start of this loop, p would be
|
| - pointing to the second colon in a double-colon, we only
|
| - satisfy the condition below if there is another
|
| - double-colon to the right (after). I.e. there is another
|
| - component that can be a class or a namespace. I.e, if at
|
| - the beginning of this loop (PASS1), we had
|
| - p->":inA::fun", we'll trigger this when p has been
|
| - advanced to point to "::fun". */
|
| - /* PASS2: we will not trigger this. */
|
| - else if ((p[0] == ':') && (p[1] == ':'))
|
| - break; /* Found double-colon. */
|
| - else
|
| - {
|
| - /* PASS2: We'll keep getting here, until P points to one of the
|
| - break characters, at which point we exit this loop. */
|
| - if (*p)
|
| - {
|
| - if (p[1] == '('
|
| - && strncmp (&p[1], CP_ANONYMOUS_NAMESPACE_STR,
|
| - CP_ANONYMOUS_NAMESPACE_LEN) == 0)
|
| - p += CP_ANONYMOUS_NAMESPACE_LEN;
|
| - else if (strchr (break_characters, *p) == NULL)
|
| - ++p;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (*p != ':')
|
| - break; /* Out of the while (1). This would happen
|
| - for instance if we have looked up
|
| - unsuccessfully all the components of the
|
| - string, and p->""(PASS2). */
|
| -
|
| - /* We get here if p points to one of the break characters or "" (i.e.,
|
| - string ended). */
|
| - /* Save restart for next time around. */
|
| - p2 = p;
|
| - /* Restore argptr as it was on entry to this function. */
|
| - *argptr = saved_arg2;
|
| - /* PASS1: at this point p->"::fun" argptr->"AAA::inA::fun",
|
| - p2->"::fun". */
|
| -
|
| - /* All ready for next pass through the loop. */
|
| - } /* while (1) */
|
| -
|
| -
|
| - /* Start of lookup in the symbol tables. */
|
| -
|
| - /* Lookup in the symbol table the substring between argptr and
|
| - p. Note, this call changes the value of argptr. */
|
| - /* Before the call, argptr->"AAA::inA::fun",
|
| - p->"", p2->"::fun". After the call: argptr->"fun", p, p2
|
| - unchanged. */
|
| - sym_classes = lookup_prefix_sym (argptr, p2, self->file_symtabs,
|
| - &class_name);
|
| - make_cleanup (VEC_cleanup (symbolp), &sym_classes);
|
| - make_cleanup (xfree, class_name);
|
| -
|
| - /* If a class has been found, then we're in case 1 above. So we
|
| - look up "fun" as a method of those classes. */
|
| - if (!VEC_empty (symbolp, sym_classes))
|
| - {
|
| - /* Arg token is not digits => try it as a function name.
|
| - Find the next token (everything up to end or next
|
| - blank). */
|
| - if (**argptr
|
| - && strchr (get_gdb_completer_quote_characters (),
|
| - **argptr) != NULL)
|
| - {
|
| - p = skip_quoted (*argptr);
|
| - *argptr = *argptr + 1;
|
| - }
|
| - else
|
| - {
|
| - /* At this point argptr->"fun". */
|
| - char *a;
|
| -
|
| - p = *argptr;
|
| - while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':'
|
| - && *p != '(')
|
| - p++;
|
| - /* At this point p->"". String ended. */
|
| - /* Nope, C++ operators could have spaces in them
|
| - ("foo::operator <" or "foo::operator delete []").
|
| - I apologize, this is a bit hacky... */
|
| - if (current_language->la_language == language_cplus
|
| - && *p == ' ' && p - 8 - *argptr + 1 > 0)
|
| - {
|
| - /* The above loop has already swallowed "operator". */
|
| - p += cp_validate_operator (p - 8) - 8;
|
| - }
|
| -
|
| - /* Keep any important naming information. */
|
| - p = keep_name_info (p, 1);
|
| - }
|
| -
|
| - /* Allocate our own copy of the substring between argptr and
|
| - p. */
|
| - copy = (char *) alloca (p - *argptr + 1);
|
| - memcpy (copy, *argptr, p - *argptr);
|
| - copy[p - *argptr] = '\0';
|
| - if (p != *argptr
|
| - && copy[p - *argptr - 1]
|
| - && strchr (get_gdb_completer_quote_characters (),
|
| - copy[p - *argptr - 1]) != NULL)
|
| - copy[p - *argptr - 1] = '\0';
|
| -
|
| - /* At this point copy->"fun", p->"". */
|
| -
|
| - /* No line number may be specified. */
|
| - *argptr = skip_spaces (p);
|
| - /* At this point arptr->"". */
|
| -
|
| - /* Look for copy as a method of sym_class. */
|
| - /* At this point copy->"fun", sym_class is "AAA:inA",
|
| - saved_arg->"AAA::inA::fun". This concludes the scanning of
|
| - the string for possible components matches. If we find it
|
| - here, we return. If not, and we are at the and of the string,
|
| - we'll lookup the whole string in the symbol tables. */
|
| -
|
| - values = find_method (self, saved_arg, copy, class_name, sym_classes);
|
| -
|
| - do_cleanups (cleanup);
|
| - return values;
|
| - } /* End if symbol found. */
|
| -
|
| -
|
| - /* We couldn't find a class, so we're in case 2 above. We check the
|
| - entire name as a symbol instead. The simplest way to do this is
|
| - to just throw an exception and let our caller fall through to
|
| - decode_variable. */
|
| -
|
| - throw_error (NOT_FOUND_ERROR, _("see caller, this text doesn't matter"));
|
| + return values;
|
| }
|
|
|
| /* An instance of this type is used when collecting prefix symbols for
|
| @@ -1750,14 +2554,14 @@ collect_one_symbol (struct symbol *sym, void *d)
|
| struct type *t;
|
|
|
| if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
|
| - return 1;
|
| + return 1; /* Continue iterating. */
|
|
|
| t = SYMBOL_TYPE (sym);
|
| CHECK_TYPEDEF (t);
|
| if (TYPE_CODE (t) != TYPE_CODE_STRUCT
|
| && TYPE_CODE (t) != TYPE_CODE_UNION
|
| && TYPE_CODE (t) != TYPE_CODE_NAMESPACE)
|
| - return 1;
|
| + return 1; /* Continue iterating. */
|
|
|
| slot = htab_find_slot (collector->unique_syms, sym, INSERT);
|
| if (!*slot)
|
| @@ -1766,49 +2570,23 @@ collect_one_symbol (struct symbol *sym, void *d)
|
| VEC_safe_push (symbolp, collector->symbols, sym);
|
| }
|
|
|
| - return 1;
|
| + return 1; /* Continue iterating. */
|
| }
|
|
|
| -/* Return the symbol corresponding to the substring of *ARGPTR ending
|
| - at P, allowing whitespace. Also, advance *ARGPTR past the symbol
|
| - name in question, the compound object separator ("::" or "."), and
|
| - whitespace. Note that *ARGPTR is changed whether or not the
|
| - this call finds anything (i.e we return NULL). As an
|
| - example, say ARGPTR is "AAA::inA::fun" and P is "::inA::fun". */
|
| +/* Return any symbols corresponding to CLASS_NAME in FILE_SYMTABS. */
|
|
|
| static VEC (symbolp) *
|
| -lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
|
| - char **class_name)
|
| +lookup_prefix_sym (struct linespec_state *state, VEC (symtab_p) *file_symtabs,
|
| + const char *class_name)
|
| {
|
| - char *p1;
|
| - char *copy;
|
| int ix;
|
| struct symtab *elt;
|
| struct decode_compound_collector collector;
|
| struct cleanup *outer;
|
| struct cleanup *cleanup;
|
| - struct block *search_block;
|
| -
|
| - /* Extract the class name. */
|
| - p1 = p;
|
| - while (p != *argptr && p[-1] == ' ')
|
| - --p;
|
| - copy = (char *) xmalloc (p - *argptr + 1);
|
| - memcpy (copy, *argptr, p - *argptr);
|
| - copy[p - *argptr] = 0;
|
| - *class_name = copy;
|
| - outer = make_cleanup (xfree, copy);
|
| -
|
| - /* Discard the class name from the argptr. */
|
| - p = p1 + (p1[0] == ':' ? 2 : 1);
|
| - p = skip_spaces (p);
|
| - *argptr = p;
|
| -
|
| - /* At this point p1->"::inA::fun", p->"inA::fun" copy->"AAA",
|
| - argptr->"inA::fun". */
|
|
|
| collector.symbols = NULL;
|
| - make_cleanup (VEC_cleanup (symbolp), &collector.symbols);
|
| + outer = make_cleanup (VEC_cleanup (symbolp), &collector.symbols);
|
|
|
| collector.unique_syms = htab_create_alloc (1, htab_hash_pointer,
|
| htab_eq_pointer, NULL,
|
| @@ -1819,12 +2597,12 @@ lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
|
| {
|
| if (elt == NULL)
|
| {
|
| - iterate_over_all_matching_symtabs (copy, STRUCT_DOMAIN,
|
| + iterate_over_all_matching_symtabs (state, class_name, STRUCT_DOMAIN,
|
| collect_one_symbol, &collector,
|
| - NULL);
|
| - iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
|
| + NULL, 0);
|
| + iterate_over_all_matching_symtabs (state, class_name, VAR_DOMAIN,
|
| collect_one_symbol, &collector,
|
| - NULL);
|
| + NULL, 0);
|
| }
|
| else
|
| {
|
| @@ -1835,9 +2613,9 @@ lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
|
| gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
|
| set_current_program_space (SYMTAB_PSPACE (elt));
|
| search_block = get_search_block (elt);
|
| - LA_ITERATE_OVER_SYMBOLS (search_block, copy, STRUCT_DOMAIN,
|
| + LA_ITERATE_OVER_SYMBOLS (search_block, class_name, STRUCT_DOMAIN,
|
| collect_one_symbol, &collector);
|
| - LA_ITERATE_OVER_SYMBOLS (search_block, copy, VAR_DOMAIN,
|
| + LA_ITERATE_OVER_SYMBOLS (search_block, class_name, VAR_DOMAIN,
|
| collect_one_symbol, &collector);
|
| }
|
| }
|
| @@ -1847,27 +2625,55 @@ lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
|
| return collector.symbols;
|
| }
|
|
|
| -/* A qsort comparison function for symbols. The resulting order does
|
| - not actually matter; we just need to be able to sort them so that
|
| - symbols with the same program space end up next to each other. */
|
| +/* A qsort comparison function for symbols. The resulting order does
|
| + not actually matter; we just need to be able to sort them so that
|
| + symbols with the same program space end up next to each other. */
|
| +
|
| +static int
|
| +compare_symbols (const void *a, const void *b)
|
| +{
|
| + struct symbol * const *sa = a;
|
| + struct symbol * const *sb = b;
|
| + uintptr_t uia, uib;
|
| +
|
| + uia = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sa));
|
| + uib = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sb));
|
| +
|
| + if (uia < uib)
|
| + return -1;
|
| + if (uia > uib)
|
| + return 1;
|
| +
|
| + uia = (uintptr_t) *sa;
|
| + uib = (uintptr_t) *sb;
|
| +
|
| + if (uia < uib)
|
| + return -1;
|
| + if (uia > uib)
|
| + return 1;
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +/* Like compare_symbols but for minimal symbols. */
|
|
|
| static int
|
| -compare_symbols (const void *a, const void *b)
|
| +compare_msymbols (const void *a, const void *b)
|
| {
|
| - struct symbol * const *sa = a;
|
| - struct symbol * const *sb = b;
|
| + const struct minsym_and_objfile *sa = a;
|
| + const struct minsym_and_objfile *sb = b;
|
| uintptr_t uia, uib;
|
|
|
| - uia = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sa));
|
| - uib = (uintptr_t) SYMTAB_PSPACE (SYMBOL_SYMTAB (*sb));
|
| + uia = (uintptr_t) sa->objfile->pspace;
|
| + uib = (uintptr_t) sa->objfile->pspace;
|
|
|
| if (uia < uib)
|
| return -1;
|
| if (uia > uib)
|
| return 1;
|
|
|
| - uia = (uintptr_t) *sa;
|
| - uib = (uintptr_t) *sb;
|
| + uia = (uintptr_t) sa->minsym;
|
| + uib = (uintptr_t) sb->minsym;
|
|
|
| if (uia < uib)
|
| return -1;
|
| @@ -1924,14 +2730,16 @@ find_superclass_methods (VEC (typep) *superclasses,
|
| do_cleanups (cleanup);
|
| }
|
|
|
| -/* This finds the method COPY in the class whose type is given by one
|
| - of the symbols in SYM_CLASSES. */
|
| +/* This finds the method METHOD_NAME in the class CLASS_NAME whose type is
|
| + given by one of the symbols in SYM_CLASSES. Matches are returned
|
| + in SYMBOLS (for debug symbols) and MINSYMS (for minimal symbols). */
|
|
|
| -static struct symtabs_and_lines
|
| -find_method (struct linespec_state *self, char *saved_arg,
|
| - char *copy, const char *class_name, VEC (symbolp) *sym_classes)
|
| +static void
|
| +find_method (struct linespec_state *self, VEC (symtab_p) *file_symtabs,
|
| + const char *class_name, const char *method_name,
|
| + VEC (symbolp) *sym_classes, VEC (symbolp) **symbols,
|
| + VEC (minsym_and_objfile_d) **minsyms)
|
| {
|
| - char *canon;
|
| struct symbol *sym;
|
| struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
|
| int ix;
|
| @@ -1939,16 +2747,6 @@ find_method (struct linespec_state *self, char *saved_arg,
|
| VEC (typep) *superclass_vec;
|
| VEC (const_char_ptr) *result_names;
|
| struct collect_info info;
|
| - char *name_iter;
|
| -
|
| - /* NAME is typed by the user: it needs to be canonicalized before
|
| - searching the symbol tables. */
|
| - canon = cp_canonicalize_string_no_typedefs (copy);
|
| - if (canon != NULL)
|
| - {
|
| - copy = canon;
|
| - make_cleanup (xfree, copy);
|
| - }
|
|
|
| /* Sort symbols so that symbols with the same program space are next
|
| to each other. */
|
| @@ -1958,11 +2756,12 @@ find_method (struct linespec_state *self, char *saved_arg,
|
| compare_symbols);
|
|
|
| info.state = self;
|
| - info.result.sals = NULL;
|
| - info.result.nelts = 0;
|
| + info.file_symtabs = file_symtabs;
|
| + info.result.symbols = NULL;
|
| + info.result.minimal_symbols = NULL;
|
|
|
| /* Iterate over all the types, looking for the names of existing
|
| - methods matching COPY. If we cannot find a direct method in a
|
| + methods matching METHOD_NAME. If we cannot find a direct method in a
|
| given program space, then we consider inherited methods; this is
|
| not ideal (ideal would be to respect C++ hiding rules), but it
|
| seems good enough and is what GDB has historically done. We only
|
| @@ -1986,7 +2785,7 @@ find_method (struct linespec_state *self, char *saved_arg,
|
| pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
|
| set_current_program_space (pspace);
|
| t = check_typedef (SYMBOL_TYPE (sym));
|
| - find_methods (t, copy, &result_names, &superclass_vec);
|
| + find_methods (t, method_name, &result_names, &superclass_vec);
|
|
|
| /* Handle all items from a single program space at once; and be
|
| sure not to miss the last batch. */
|
| @@ -1998,7 +2797,8 @@ find_method (struct linespec_state *self, char *saved_arg,
|
| /* If we did not find a direct implementation anywhere in
|
| this program space, consider superclasses. */
|
| if (VEC_length (const_char_ptr, result_names) == last_result_len)
|
| - find_superclass_methods (superclass_vec, copy, &result_names);
|
| + find_superclass_methods (superclass_vec, method_name,
|
| + &result_names);
|
|
|
| /* We have a list of candidate symbol names, so now we
|
| iterate over the symbol tables looking for all
|
| @@ -2010,31 +2810,18 @@ find_method (struct linespec_state *self, char *saved_arg,
|
| }
|
| }
|
|
|
| - if (info.result.nelts > 0)
|
| + if (!VEC_empty (symbolp, info.result.symbols)
|
| + || !VEC_empty (minsym_and_objfile_d, info.result.minimal_symbols))
|
| {
|
| - if (self->canonical)
|
| - {
|
| - self->canonical->pre_expanded = 1;
|
| - if (self->user_filename)
|
| - self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", self->user_filename, saved_arg);
|
| - else
|
| - self->canonical->addr_string = xstrdup (saved_arg);
|
| - }
|
| -
|
| + *symbols = info.result.symbols;
|
| + *minsyms = info.result.minimal_symbols;
|
| do_cleanups (cleanup);
|
| -
|
| - return info.result;
|
| + return;
|
| }
|
|
|
| - if (copy[0] == '~')
|
| - cplusplus_error (saved_arg,
|
| - "the class `%s' does not have destructor defined\n",
|
| - class_name);
|
| - else
|
| - cplusplus_error (saved_arg,
|
| - "the class %s does not have any method named %s\n",
|
| - class_name, copy);
|
| + /* Throw an NOT_FOUND_ERROR. This will be caught by the caller
|
| + and other attempts to locate the symbol will be made. */
|
| + throw_error (NOT_FOUND_ERROR, _("see caller, this text doesn't matter"));
|
| }
|
|
|
|
|
| @@ -2096,487 +2883,193 @@ collect_symtabs_from_filename (const char *file)
|
| return collector.symtabs;
|
| }
|
|
|
| -/* Return all the symtabs associated to the filename given by the
|
| - substring of *ARGPTR ending at P, and advance ARGPTR past that
|
| - filename. */
|
| +/* Return all the symtabs associated to the FILENAME. */
|
|
|
| static VEC (symtab_p) *
|
| -symtabs_from_filename (char **argptr, char *p, int is_quote_enclosed,
|
| - char **user_filename)
|
| -{
|
| - char *p1;
|
| - char *copy;
|
| - struct cleanup *outer;
|
| - VEC (symtab_p) *result;
|
| -
|
| - p1 = p;
|
| - while (p != *argptr && p[-1] == ' ')
|
| - --p;
|
| - if ((*p == '"') && is_quote_enclosed)
|
| - --p;
|
| - copy = xmalloc (p - *argptr + 1);
|
| - outer = make_cleanup (xfree, copy);
|
| - memcpy (copy, *argptr, p - *argptr);
|
| - /* It may have the ending quote right after the file name. */
|
| - if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
|
| - || copy[p - *argptr - 1] == '\'')
|
| - copy[p - *argptr - 1] = 0;
|
| - else
|
| - copy[p - *argptr] = 0;
|
| -
|
| - result = collect_symtabs_from_filename (copy);
|
| -
|
| - if (VEC_empty (symtab_p, result))
|
| - {
|
| - if (!have_full_symbols () && !have_partial_symbols ())
|
| - throw_error (NOT_FOUND_ERROR,
|
| - _("No symbol table is loaded. "
|
| - "Use the \"file\" command."));
|
| - throw_error (NOT_FOUND_ERROR, _("No source file named %s."), copy);
|
| - }
|
| -
|
| - /* Discard the file name from the arg. */
|
| - if (*p1 == '\0')
|
| - *argptr = p1;
|
| - else
|
| - *argptr = skip_spaces (p1 + 1);
|
| -
|
| - discard_cleanups (outer);
|
| - *user_filename = copy;
|
| - return result;
|
| -}
|
| -
|
| -/* A callback used by iterate_over_all_matching_symtabs that collects
|
| - symbols for find_function_symbols. */
|
| -
|
| -static int
|
| -collect_function_symbols (struct symbol *sym, void *arg)
|
| -{
|
| - VEC (symbolp) **syms = arg;
|
| -
|
| - if (SYMBOL_CLASS (sym) == LOC_BLOCK)
|
| - VEC_safe_push (symbolp, *syms, sym);
|
| -
|
| - return 1;
|
| -}
|
| -
|
| -/* Look up a function symbol in *ARGPTR. If found, advance *ARGPTR
|
| - and return the symbol. If not found, return NULL. */
|
| -
|
| -static VEC (symbolp) *
|
| -find_function_symbols (char **argptr, char *p, int is_quote_enclosed,
|
| - char **user_function)
|
| -{
|
| - char *p1;
|
| - char *copy;
|
| - VEC (symbolp) *result = NULL;
|
| -
|
| - p1 = p;
|
| - while (p != *argptr && p[-1] == ' ')
|
| - --p;
|
| - if ((*p == '"') && is_quote_enclosed)
|
| - --p;
|
| - copy = (char *) xmalloc (p - *argptr + 1);
|
| - *user_function = copy;
|
| - memcpy (copy, *argptr, p - *argptr);
|
| - /* It may have the ending quote right after the file name. */
|
| - if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
|
| - || copy[p - *argptr - 1] == '\'')
|
| - copy[p - *argptr - 1] = 0;
|
| - else
|
| - copy[p - *argptr] = 0;
|
| -
|
| - iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
|
| - collect_function_symbols, &result, NULL);
|
| -
|
| - if (VEC_empty (symbolp, result))
|
| - VEC_free (symbolp, result);
|
| - else
|
| - {
|
| - /* Discard the file name from the arg. */
|
| - *argptr = skip_spaces (p1 + 1);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -
|
| -
|
| -/* A helper for decode_all_digits that handles the 'list_mode' case. */
|
| -
|
| -static void
|
| -decode_digits_list_mode (struct linespec_state *self,
|
| - struct symtabs_and_lines *values,
|
| - struct symtab_and_line val)
|
| -{
|
| - int ix;
|
| - struct symtab *elt;
|
| -
|
| - gdb_assert (self->list_mode);
|
| -
|
| - for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
|
| - {
|
| - /* The logic above should ensure this. */
|
| - gdb_assert (elt != NULL);
|
| -
|
| - set_current_program_space (SYMTAB_PSPACE (elt));
|
| -
|
| - /* Simplistic search just for the list command. */
|
| - val.symtab = find_line_symtab (elt, val.line, NULL, NULL);
|
| - if (val.symtab == NULL)
|
| - val.symtab = elt;
|
| - val.pspace = SYMTAB_PSPACE (elt);
|
| - val.pc = 0;
|
| - val.explicit_line = 1;
|
| -
|
| - add_sal_to_sals (self, values, &val, NULL);
|
| - }
|
| -}
|
| -
|
| -/* A helper for decode_all_digits that iterates over the symtabs,
|
| - adding lines to the VEC. */
|
| -
|
| -static void
|
| -decode_digits_ordinary (struct linespec_state *self,
|
| - int line,
|
| - struct symtabs_and_lines *sals,
|
| - struct linetable_entry **best_entry)
|
| -{
|
| - int ix;
|
| - struct symtab *elt;
|
| -
|
| - for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
|
| - {
|
| - int i;
|
| - VEC (CORE_ADDR) *pcs;
|
| - CORE_ADDR pc;
|
| -
|
| - /* The logic above should ensure this. */
|
| - gdb_assert (elt != NULL);
|
| -
|
| - set_current_program_space (SYMTAB_PSPACE (elt));
|
| -
|
| - pcs = find_pcs_for_symtab_line (elt, line, best_entry);
|
| - for (i = 0; VEC_iterate (CORE_ADDR, pcs, i, pc); ++i)
|
| - {
|
| - struct symtab_and_line sal;
|
| -
|
| - init_sal (&sal);
|
| - sal.pspace = SYMTAB_PSPACE (elt);
|
| - sal.symtab = elt;
|
| - sal.line = line;
|
| - sal.pc = pc;
|
| - add_sal_to_sals_basic (sals, &sal);
|
| - }
|
| -
|
| - VEC_free (CORE_ADDR, pcs);
|
| - }
|
| -}
|
| -
|
| -/* This decodes a line where the argument is all digits (possibly
|
| - preceded by a sign). Q should point to the end of those digits;
|
| - the other arguments are as usual. */
|
| -
|
| -static struct symtabs_and_lines
|
| -decode_all_digits (struct linespec_state *self,
|
| - char **argptr,
|
| - char *q)
|
| +symtabs_from_filename (const char *filename)
|
| {
|
| - struct symtabs_and_lines values;
|
| - struct symtab_and_line val;
|
| - int use_default = 0;
|
| - char *saved_arg = *argptr;
|
| -
|
| - enum sign
|
| - {
|
| - none, plus, minus
|
| - }
|
| - sign = none;
|
| -
|
| - init_sal (&val);
|
| - values.sals = NULL;
|
| - values.nelts = 0;
|
| -
|
| - /* This is where we need to make sure that we have good defaults.
|
| - We must guarantee that this section of code is never executed
|
| - when we are called with just a function name, since
|
| - set_default_source_symtab_and_line uses
|
| - select_source_symtab that calls us with such an argument. */
|
| -
|
| - if (VEC_length (symtab_p, self->file_symtabs) == 1
|
| - && VEC_index (symtab_p, self->file_symtabs, 0) == NULL)
|
| - {
|
| - set_current_program_space (self->program_space);
|
| -
|
| - /* Make sure we have at least a default source file. */
|
| - set_default_source_symtab_and_line ();
|
| - initialize_defaults (&self->default_symtab, &self->default_line);
|
| - VEC_pop (symtab_p, self->file_symtabs);
|
| - VEC_free (symtab_p, self->file_symtabs);
|
| - self->file_symtabs
|
| - = collect_symtabs_from_filename (self->default_symtab->filename);
|
| - use_default = 1;
|
| - }
|
| -
|
| - if (**argptr == '+')
|
| - sign = plus, (*argptr)++;
|
| - else if (**argptr == '-')
|
| - sign = minus, (*argptr)++;
|
| - val.line = atoi (*argptr);
|
| - switch (sign)
|
| - {
|
| - case plus:
|
| - if (q == *argptr)
|
| - val.line = 5;
|
| - if (use_default)
|
| - val.line = self->default_line + val.line;
|
| - break;
|
| - case minus:
|
| - if (q == *argptr)
|
| - val.line = 15;
|
| - if (use_default)
|
| - val.line = self->default_line - val.line;
|
| - else
|
| - val.line = 1;
|
| - break;
|
| - case none:
|
| - break; /* No need to adjust val.line. */
|
| - }
|
| -
|
| - *argptr = skip_spaces (q);
|
| -
|
| - if (self->list_mode)
|
| - decode_digits_list_mode (self, &values, val);
|
| - else
|
| - {
|
| - struct linetable_entry *best_entry = NULL;
|
| - int *filter;
|
| - struct block **blocks;
|
| - struct cleanup *cleanup;
|
| - struct symtabs_and_lines intermediate_results;
|
| - int i, j;
|
| -
|
| - intermediate_results.sals = NULL;
|
| - intermediate_results.nelts = 0;
|
| -
|
| - decode_digits_ordinary (self, val.line, &intermediate_results,
|
| - &best_entry);
|
| - if (intermediate_results.nelts == 0 && best_entry != NULL)
|
| - decode_digits_ordinary (self, best_entry->line, &intermediate_results,
|
| - &best_entry);
|
| -
|
| - cleanup = make_cleanup (xfree, intermediate_results.sals);
|
| -
|
| - /* For optimized code, compiler can scatter one source line
|
| - accross disjoint ranges of PC values, even when no duplicate
|
| - functions or inline functions are involved. For example,
|
| - 'for (;;)' inside non-template non-inline non-ctor-or-dtor
|
| - function can result in two PC ranges. In this case, we don't
|
| - want to set breakpoint on first PC of each range. To filter
|
| - such cases, we use containing blocks -- for each PC found
|
| - above we see if there are other PCs that are in the same
|
| - block. If yes, the other PCs are filtered out. */
|
| -
|
| - filter = xmalloc (intermediate_results.nelts * sizeof (int));
|
| - make_cleanup (xfree, filter);
|
| - blocks = xmalloc (intermediate_results.nelts * sizeof (struct block *));
|
| - make_cleanup (xfree, blocks);
|
| -
|
| - for (i = 0; i < intermediate_results.nelts; ++i)
|
| - {
|
| - set_current_program_space (intermediate_results.sals[i].pspace);
|
| -
|
| - filter[i] = 1;
|
| - blocks[i] = block_for_pc_sect (intermediate_results.sals[i].pc,
|
| - intermediate_results.sals[i].section);
|
| - }
|
| -
|
| - for (i = 0; i < intermediate_results.nelts; ++i)
|
| - {
|
| - if (blocks[i] != NULL)
|
| - for (j = i + 1; j < intermediate_results.nelts; ++j)
|
| - {
|
| - if (blocks[j] == blocks[i])
|
| - {
|
| - filter[j] = 0;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - for (i = 0; i < intermediate_results.nelts; ++i)
|
| - if (filter[i])
|
| - {
|
| - struct symbol *sym = (blocks[i]
|
| - ? block_containing_function (blocks[i])
|
| - : NULL);
|
| -
|
| - if (self->funfirstline)
|
| - skip_prologue_sal (&intermediate_results.sals[i]);
|
| - /* Make sure the line matches the request, not what was
|
| - found. */
|
| - intermediate_results.sals[i].line = val.line;
|
| - add_sal_to_sals (self, &values, &intermediate_results.sals[i],
|
| - sym ? SYMBOL_NATURAL_NAME (sym) : NULL);
|
| - }
|
| -
|
| - do_cleanups (cleanup);
|
| - }
|
| -
|
| - if (values.nelts == 0)
|
| - {
|
| - if (self->user_filename)
|
| - throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
|
| - val.line, self->user_filename);
|
| - else
|
| - throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
|
| - val.line);
|
| - }
|
| + VEC (symtab_p) *result;
|
| +
|
| + result = collect_symtabs_from_filename (filename);
|
|
|
| - if (self->canonical)
|
| + if (VEC_empty (symtab_p, result))
|
| {
|
| - char *copy = savestring (saved_arg, q - saved_arg);
|
| -
|
| - self->canonical->pre_expanded = 1;
|
| - gdb_assert (self->user_filename || use_default);
|
| - self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", (self->user_filename
|
| - ? self->user_filename
|
| - : self->default_symtab->filename),
|
| - copy);
|
| - xfree (copy);
|
| + if (!have_full_symbols () && !have_partial_symbols ())
|
| + 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);
|
| }
|
|
|
| - return values;
|
| + return result;
|
| }
|
|
|
| -
|
| -
|
| -/* Decode a linespec starting with a dollar sign. */
|
| +/* Look up a function symbol named NAME in symtabs FILE_SYMTABS. Matching
|
| + debug symbols are returned in SYMBOLS. Matching minimal symbols are
|
| + returned in MINSYMS. */
|
|
|
| -static struct symtabs_and_lines
|
| -decode_dollar (struct linespec_state *self, char *copy)
|
| +static void
|
| +find_function_symbols (struct linespec_state *state,
|
| + VEC (symtab_p) *file_symtabs, const char *name,
|
| + VEC (symbolp) **symbols,
|
| + VEC (minsym_and_objfile_d) **minsyms)
|
| {
|
| - LONGEST valx;
|
| - int index = 0;
|
| - struct symtabs_and_lines values;
|
| - struct symtab_and_line val;
|
| - char *p;
|
| - struct symbol *sym;
|
| - struct minimal_symbol *msymbol;
|
| - int ix;
|
| - struct symtab *elt;
|
| + struct collect_info info;
|
| + VEC (const_char_ptr) *symbol_names = NULL;
|
| + struct cleanup *cleanup = make_cleanup (VEC_cleanup (const_char_ptr),
|
| + &symbol_names);
|
|
|
| - p = (copy[1] == '$') ? copy + 2 : copy + 1;
|
| - while (*p >= '0' && *p <= '9')
|
| - p++;
|
| - if (!*p) /* Reached end of token without hitting non-digit. */
|
| - {
|
| - /* We have a value history reference. */
|
| - struct value *val_history;
|
| + info.state = state;
|
| + info.result.symbols = NULL;
|
| + info.result.minimal_symbols = NULL;
|
| + info.file_symtabs = file_symtabs;
|
|
|
| - sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
|
| - val_history = access_value_history ((copy[1] == '$') ? -index : index);
|
| - if (TYPE_CODE (value_type (val_history)) != TYPE_CODE_INT)
|
| - error (_("History values used in line "
|
| - "specs must have integer values."));
|
| - valx = value_as_long (val_history);
|
| + /* Try NAME as an Objective-C selector. */
|
| + find_imps ((char *) name, &symbol_names);
|
| + if (!VEC_empty (const_char_ptr, symbol_names))
|
| + add_all_symbol_names_from_pspace (&info, NULL, symbol_names);
|
| + else
|
| + add_matching_symbols_to_info (name, &info, NULL);
|
| +
|
| + do_cleanups (cleanup);
|
| +
|
| + if (VEC_empty (symbolp, info.result.symbols))
|
| + {
|
| + VEC_free (symbolp, info.result.symbols);
|
| + *symbols = NULL;
|
| }
|
| else
|
| + *symbols = info.result.symbols;
|
| +
|
| + if (VEC_empty (minsym_and_objfile_d, info.result.minimal_symbols))
|
| {
|
| - /* Not all digits -- may be user variable/function or a
|
| - convenience variable. */
|
| + VEC_free (minsym_and_objfile_d, info.result.minimal_symbols);
|
| + *minsyms = NULL;
|
| + }
|
| + else
|
| + *minsyms = info.result.minimal_symbols;
|
| +}
|
|
|
| - volatile struct gdb_exception exc;
|
| +/* Find all symbols named NAME in FILE_SYMTABS, returning debug symbols
|
| + in SYMBOLS and minimal symbols in MINSYMS. */
|
|
|
| - /* Avoid "may be used uninitialized" warning. */
|
| - values.sals = NULL;
|
| - values.nelts = 0;
|
| +void
|
| +find_linespec_symbols (struct linespec_state *state,
|
| + VEC (symtab_p) *file_symtabs,
|
| + const char *name,
|
| + VEC (symbolp) **symbols,
|
| + VEC (minsym_and_objfile_d) **minsyms)
|
| +{
|
| + char *klass, *method, *canon;
|
| + const char *lookup_name, *last, *p, *scope_op;
|
| + struct cleanup *cleanup;
|
| + VEC (symbolp) *classes;
|
| + volatile struct gdb_exception except;
|
|
|
| - TRY_CATCH (exc, RETURN_MASK_ERROR)
|
| - {
|
| - values = decode_variable (self, copy);
|
| - }
|
| + cleanup = demangle_for_lookup (name, state->language->la_language,
|
| + &lookup_name);
|
| + if (state->language->la_language == language_ada)
|
| + {
|
| + /* In Ada, the symbol lookups are performed using the encoded
|
| + name rather than the demangled name. */
|
| + lookup_name = ada_name_for_lookup (name);
|
| + make_cleanup (xfree, (void *) lookup_name);
|
| + }
|
|
|
| - if (exc.reason == 0)
|
| - return values;
|
| + canon = cp_canonicalize_string_no_typedefs (lookup_name);
|
| + if (canon != NULL)
|
| + {
|
| + lookup_name = canon;
|
| + cleanup = make_cleanup (xfree, canon);
|
| + }
|
|
|
| - if (exc.error != NOT_FOUND_ERROR)
|
| - throw_exception (exc);
|
| + /* See if we can find a scope operator and break this symbol
|
| + name into namespaces${SCOPE_OPERATOR}class_name and method_name. */
|
| + scope_op = "::";
|
| + p = find_toplevel_string (lookup_name, scope_op);
|
| + if (p == NULL)
|
| + {
|
| + /* No C++ scope operator. Try Java. */
|
| + scope_op = ".";
|
| + p = find_toplevel_string (lookup_name, scope_op);
|
| + }
|
|
|
| - /* Not a user variable or function -- must be convenience variable. */
|
| - if (!get_internalvar_integer (lookup_internalvar (copy + 1), &valx))
|
| - error (_("Convenience variables used in line "
|
| - "specs must have integer values."));
|
| + last = NULL;
|
| + while (p != NULL)
|
| + {
|
| + last = p;
|
| + p = find_toplevel_string (p + strlen (scope_op), scope_op);
|
| }
|
|
|
| - init_sal (&val);
|
| + /* If no scope operator was found, lookup the name as a symbol. */
|
| + if (last == NULL)
|
| + {
|
| + find_function_symbols (state, file_symtabs, lookup_name,
|
| + symbols, minsyms);
|
| + do_cleanups (cleanup);
|
| + return;
|
| + }
|
|
|
| - values.sals = NULL;
|
| - values.nelts = 0;
|
| + /* NAME points to the class name.
|
| + LAST points to the method name. */
|
| + klass = xmalloc ((last - lookup_name + 1) * sizeof (char));
|
| + make_cleanup (xfree, klass);
|
| + strncpy (klass, lookup_name, last - lookup_name);
|
| + klass[last - lookup_name] = '\0';
|
| +
|
| + /* Skip past the scope operator. */
|
| + last += strlen (scope_op);
|
| + method = xmalloc ((strlen (last) + 1) * sizeof (char));
|
| + make_cleanup (xfree, method);
|
| + strcpy (method, last);
|
|
|
| - for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
|
| + /* Find a list of classes named KLASS. */
|
| + classes = lookup_prefix_sym (state, file_symtabs, klass);
|
| + make_cleanup (VEC_cleanup (symbolp), &classes);
|
| + if (!VEC_empty (symbolp, classes))
|
| {
|
| - if (elt == NULL)
|
| + /* Now locate a list of suitable methods named METHOD. */
|
| + TRY_CATCH (except, RETURN_MASK_ERROR)
|
| {
|
| - elt = self->default_symtab;
|
| - set_current_program_space (self->program_space);
|
| + find_method (state, file_symtabs, klass, method, classes,
|
| + symbols, minsyms);
|
| }
|
| - else
|
| - set_current_program_space (SYMTAB_PSPACE (elt));
|
| -
|
| - /* Either history value or convenience value from above, in valx. */
|
| - val.symtab = elt;
|
| - val.line = valx;
|
| - val.pc = 0;
|
| - val.pspace = elt ? SYMTAB_PSPACE (elt) : current_program_space;
|
|
|
| - add_sal_to_sals (self, &values, &val, NULL);
|
| - }
|
| -
|
| - if (self->canonical)
|
| - {
|
| - self->canonical->pre_expanded = 1;
|
| - if (self->user_filename)
|
| - self->canonical->addr_string = xstrprintf ("%s:%s",
|
| - self->user_filename, copy);
|
| - else
|
| - self->canonical->addr_string = xstrdup (copy);
|
| + /* If successful, we're done. If NOT_FOUND_ERROR
|
| + was not thrown, rethrow the exception that we did get.
|
| + Otherwise, fall back to looking up the entire name as a symbol.
|
| + This can happen with namespace::function. */
|
| + if (except.reason >= 0)
|
| + {
|
| + do_cleanups (cleanup);
|
| + return;
|
| + }
|
| + else if (except.error != NOT_FOUND_ERROR)
|
| + throw_exception (except);
|
| }
|
|
|
| - return values;
|
| + /* We couldn't find a class, so we check the entire name as a symbol
|
| + instead. */
|
| + find_function_symbols (state, file_symtabs, lookup_name, symbols, minsyms);
|
| + do_cleanups (cleanup);
|
| }
|
|
|
| -
|
| -
|
| -/* A helper for decode_line_1 that tries to find a label. The label
|
| - is searched for in the current block.
|
| - FUNCTION_SYMBOLS is a list of the enclosing functions; or NULL if none
|
| - specified.
|
| - COPY is the name of the label to find.
|
| - CANONICAL is the same as the "canonical" argument to decode_line_1.
|
| - RESULT is a pointer to a symtabs_and_lines structure which will be
|
| - filled in on success.
|
| - This function returns 1 if a label was found, 0 otherwise. */
|
| +/* Return all labels named NAME in FUNCTION_SYMBOLS. Return the
|
| + actual function symbol in which the label was found in LABEL_FUNC_RET. */
|
|
|
| -static int
|
| -decode_label (struct linespec_state *self,
|
| - VEC (symbolp) *function_symbols, char *copy,
|
| - struct symtabs_and_lines *result)
|
| +static VEC (symbolp) *
|
| +find_label_symbols (struct linespec_state *self,
|
| + VEC (symbolp) *function_symbols,
|
| + VEC (symbolp) **label_funcs_ret, const char *name)
|
| {
|
| - struct symbol *fn_sym;
|
| int ix;
|
| + struct block *block;
|
| + struct symbol *sym;
|
| + struct symbol *fn_sym;
|
| + VEC (symbolp) *result = NULL;
|
|
|
| if (function_symbols == NULL)
|
| {
|
| - struct block *block;
|
| - struct symbol *sym;
|
| - struct symtab_and_line sal;
|
| - struct symtabs_and_lines values;
|
| -
|
| - values.nelts = 0;
|
| - values.sals = NULL;
|
| -
|
| set_current_program_space (self->program_space);
|
| block = get_search_block (NULL);
|
|
|
| @@ -2585,69 +3078,171 @@ decode_label (struct linespec_state *self,
|
| block = BLOCK_SUPERBLOCK (block))
|
| ;
|
| if (!block)
|
| - return 0;
|
| + return NULL;
|
| fn_sym = BLOCK_FUNCTION (block);
|
|
|
| - sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
|
| + sym = lookup_symbol (name, block, LABEL_DOMAIN, 0);
|
|
|
| - if (sym == NULL)
|
| - return 0;
|
| -
|
| - symbol_to_sal (&sal, self->funfirstline, sym);
|
| - add_sal_to_sals (self, &values, &sal,
|
| - SYMBOL_NATURAL_NAME (fn_sym));
|
| -
|
| - if (self->canonical)
|
| + if (sym != NULL)
|
| {
|
| - self->canonical->special_display = 1;
|
| - self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", SYMBOL_NATURAL_NAME (fn_sym),
|
| - copy);
|
| + VEC_safe_push (symbolp, result, sym);
|
| + VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
|
| + }
|
| + }
|
| + else
|
| + {
|
| + for (ix = 0;
|
| + VEC_iterate (symbolp, function_symbols, ix, fn_sym); ++ix)
|
| + {
|
| + set_current_program_space (SYMTAB_PSPACE (SYMBOL_SYMTAB (fn_sym)));
|
| + block = SYMBOL_BLOCK_VALUE (fn_sym);
|
| + sym = lookup_symbol (name, block, LABEL_DOMAIN, 0);
|
| +
|
| + if (sym != NULL)
|
| + {
|
| + VEC_safe_push (symbolp, result, sym);
|
| + VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
|
| + }
|
| }
|
| + }
|
|
|
| - *result = values;
|
| + return result;
|
| +}
|
|
|
| - return 1;
|
| +
|
| +
|
| +/* A helper for create_sals_line_offset that handles the 'list_mode' case. */
|
| +
|
| +static void
|
| +decode_digits_list_mode (struct linespec_state *self,
|
| + linespec_p ls,
|
| + struct symtabs_and_lines *values,
|
| + struct symtab_and_line val)
|
| +{
|
| + int ix;
|
| + struct symtab *elt;
|
| +
|
| + gdb_assert (self->list_mode);
|
| +
|
| + for (ix = 0; VEC_iterate (symtab_p, ls->file_symtabs, ix, elt);
|
| + ++ix)
|
| + {
|
| + /* The logic above should ensure this. */
|
| + gdb_assert (elt != NULL);
|
| +
|
| + set_current_program_space (SYMTAB_PSPACE (elt));
|
| +
|
| + /* Simplistic search just for the list command. */
|
| + val.symtab = find_line_symtab (elt, val.line, NULL, NULL);
|
| + if (val.symtab == NULL)
|
| + val.symtab = elt;
|
| + val.pspace = SYMTAB_PSPACE (elt);
|
| + val.pc = 0;
|
| + val.explicit_line = 1;
|
| +
|
| + add_sal_to_sals (self, values, &val, NULL);
|
| }
|
| +}
|
| +
|
| +/* A helper for create_sals_line_offset that iterates over the symtabs,
|
| + adding lines to the VEC. */
|
|
|
| - result->sals = NULL;
|
| - result->nelts = 0;
|
| +static void
|
| +decode_digits_ordinary (struct linespec_state *self,
|
| + linespec_p ls,
|
| + int line,
|
| + struct symtabs_and_lines *sals,
|
| + struct linetable_entry **best_entry)
|
| +{
|
| + int ix;
|
| + struct symtab *elt;
|
|
|
| - for (ix = 0; VEC_iterate (symbolp, function_symbols, ix, fn_sym); ++ix)
|
| + for (ix = 0; VEC_iterate (symtab_p, ls->file_symtabs, ix, elt); ++ix)
|
| {
|
| - struct block *block;
|
| - struct symbol *sym;
|
| + int i;
|
| + VEC (CORE_ADDR) *pcs;
|
| + CORE_ADDR pc;
|
| +
|
| + /* The logic above should ensure this. */
|
| + gdb_assert (elt != NULL);
|
|
|
| - set_current_program_space (SYMTAB_PSPACE (SYMBOL_SYMTAB (fn_sym)));
|
| - block = SYMBOL_BLOCK_VALUE (fn_sym);
|
| - sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
|
| + set_current_program_space (SYMTAB_PSPACE (elt));
|
|
|
| - if (sym != NULL)
|
| + pcs = find_pcs_for_symtab_line (elt, line, best_entry);
|
| + for (i = 0; VEC_iterate (CORE_ADDR, pcs, i, pc); ++i)
|
| {
|
| struct symtab_and_line sal;
|
| - char *symname;
|
| -
|
| - symbol_to_sal (&sal, self->funfirstline, sym);
|
| - symname = xstrprintf ("%s:%s",
|
| - SYMBOL_NATURAL_NAME (fn_sym),
|
| - SYMBOL_NATURAL_NAME (sym));
|
| - add_sal_to_sals (self, result, &sal, symname);
|
| - xfree (symname);
|
| +
|
| + init_sal (&sal);
|
| + sal.pspace = SYMTAB_PSPACE (elt);
|
| + sal.symtab = elt;
|
| + sal.line = line;
|
| + sal.pc = pc;
|
| + add_sal_to_sals_basic (sals, &sal);
|
| }
|
| +
|
| + VEC_free (CORE_ADDR, pcs);
|
| }
|
| +}
|
|
|
| - if (self->canonical && result->nelts > 0)
|
| +
|
| +
|
| +/* Return the line offset represented by VARIABLE. */
|
| +
|
| +static struct line_offset
|
| +linespec_parse_variable (struct linespec_state *self, const char *variable)
|
| +{
|
| + int index = 0;
|
| + const char *p;
|
| + struct line_offset offset = {0, LINE_OFFSET_NONE};
|
| +
|
| + p = (variable[1] == '$') ? variable + 2 : variable + 1;
|
| + if (*p == '$')
|
| + ++p;
|
| + while (*p >= '0' && *p <= '9')
|
| + ++p;
|
| + if (!*p) /* Reached end of token without hitting non-digit. */
|
| {
|
| - self->canonical->pre_expanded = 1;
|
| - self->canonical->special_display = 1;
|
| + /* We have a value history reference. */
|
| + struct value *val_history;
|
|
|
| - gdb_assert (self->user_function);
|
| - self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", self->user_function, copy);
|
| + sscanf ((variable[1] == '$') ? variable + 2 : variable + 1, "%d", &index);
|
| + val_history
|
| + = access_value_history ((variable[1] == '$') ? -index : index);
|
| + if (TYPE_CODE (value_type (val_history)) != TYPE_CODE_INT)
|
| + error (_("History values used in line "
|
| + "specs must have integer values."));
|
| + offset.offset = value_as_long (val_history);
|
| + }
|
| + else
|
| + {
|
| + /* Not all digits -- may be user variable/function or a
|
| + convenience variable. */
|
| + LONGEST valx;
|
| + struct internalvar *ivar;
|
| +
|
| + /* Try it as a convenience variable. If it is not a convenience
|
| + variable, return and allow normal symbol lookup to occur. */
|
| + ivar = lookup_only_internalvar (variable + 1);
|
| + if (ivar == NULL)
|
| + /* No internal variable with that name. Mark the offset
|
| + as unknown to allow the name to be looked up as a symbol. */
|
| + offset.sign = LINE_OFFSET_UNKNOWN;
|
| + else
|
| + {
|
| + /* We found a valid variable name. If it is not an integer,
|
| + throw an error. */
|
| + if (!get_internalvar_integer (ivar, &valx))
|
| + error (_("Convenience variables used in line "
|
| + "specs must have integer values."));
|
| + else
|
| + offset.offset = valx;
|
| + }
|
| }
|
|
|
| - return result->nelts > 0;
|
| + return offset;
|
| }
|
| +
|
|
|
| /* A callback used to possibly add a symbol to the results. */
|
|
|
| @@ -2655,20 +3250,16 @@ static int
|
| collect_symbols (struct symbol *sym, void *data)
|
| {
|
| struct collect_info *info = data;
|
| - struct symtab_and_line sal;
|
|
|
| - if (symbol_to_sal (&sal, info->state->funfirstline, sym)
|
| - && maybe_add_address (info->state->addr_set,
|
| - SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
|
| - sal.pc))
|
| - add_sal_to_sals (info->state, &info->result, &sal,
|
| - SYMBOL_NATURAL_NAME (sym));
|
| -
|
| - return 1;
|
| + /* In list mode, add all matching symbols, regardless of class.
|
| + This allows the user to type "list a_global_variable". */
|
| + if (SYMBOL_CLASS (sym) == LOC_BLOCK || info->state->list_mode)
|
| + VEC_safe_push (symbolp, info->result.symbols, sym);
|
| + return 1; /* Continue iterating. */
|
| }
|
|
|
| -/* We've found a minimal symbol MSYMBOL to associate with our
|
| - linespec; add it to the result symtabs_and_lines. */
|
| +/* We've found a minimal symbol MSYMBOL in OBJFILE to associate with our
|
| + linespec; return the SAL in RESULT. */
|
|
|
| static void
|
| minsym_found (struct linespec_state *self, struct objfile *objfile,
|
| @@ -2696,17 +3287,6 @@ minsym_found (struct linespec_state *self, struct objfile *objfile,
|
| add_sal_to_sals (self, result, &sal, SYMBOL_NATURAL_NAME (msymbol));
|
| }
|
|
|
| -/* A helper struct which just holds a minimal symbol and the object
|
| - file from which it came. */
|
| -
|
| -typedef struct minsym_and_objfile
|
| -{
|
| - struct minimal_symbol *minsym;
|
| - struct objfile *objfile;
|
| -} minsym_and_objfile_d;
|
| -
|
| -DEF_VEC_O (minsym_and_objfile_d);
|
| -
|
| /* A helper struct to pass some data through
|
| iterate_over_minimal_symbols. */
|
|
|
| @@ -2859,8 +3439,8 @@ search_minsyms_for_name (struct collect_info *info, const char *name,
|
| if (classify_mtype (MSYMBOL_TYPE (item->minsym)) != classification)
|
| break;
|
|
|
| - minsym_found (info->state, item->objfile, item->minsym,
|
| - &info->result);
|
| + VEC_safe_push (minsym_and_objfile_d,
|
| + info->result.minimal_symbols, item);
|
| }
|
| }
|
|
|
| @@ -2880,15 +3460,13 @@ add_matching_symbols_to_info (const char *name,
|
| int ix;
|
| struct symtab *elt;
|
|
|
| - for (ix = 0; VEC_iterate (symtab_p, info->state->file_symtabs, ix, elt); ++ix)
|
| + for (ix = 0; VEC_iterate (symtab_p, info->file_symtabs, ix, elt); ++ix)
|
| {
|
| - struct symbol *sym;
|
| -
|
| if (elt == NULL)
|
| {
|
| - iterate_over_all_matching_symtabs (name, VAR_DOMAIN,
|
| + iterate_over_all_matching_symtabs (info->state, name, VAR_DOMAIN,
|
| collect_symbols, info,
|
| - pspace);
|
| + pspace, 1);
|
| search_minsyms_for_name (info, name, pspace);
|
| }
|
| else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt))
|
| @@ -2904,67 +3482,6 @@ add_matching_symbols_to_info (const char *name,
|
| }
|
| }
|
|
|
| -/* Decode a linespec that's a variable. If FILE_SYMTAB is non-NULL,
|
| - look in that symtab's static variables first. */
|
| -
|
| -static struct symtabs_and_lines
|
| -decode_variable (struct linespec_state *self, char *copy)
|
| -{
|
| - struct collect_info info;
|
| - const char *lookup_name;
|
| - char *canon;
|
| - struct cleanup *cleanup;
|
| -
|
| - info.state = self;
|
| - info.result.sals = NULL;
|
| - info.result.nelts = 0;
|
| -
|
| - cleanup = demangle_for_lookup (copy, current_language->la_language,
|
| - &lookup_name);
|
| - if (current_language->la_language == language_ada)
|
| - {
|
| - /* In Ada, the symbol lookups are performed using the encoded
|
| - name rather than the demangled name. */
|
| - lookup_name = ada_name_for_lookup (copy);
|
| - make_cleanup (xfree, (void *) lookup_name);
|
| - }
|
| -
|
| - canon = cp_canonicalize_string_no_typedefs (lookup_name);
|
| - if (canon != NULL)
|
| - {
|
| - make_cleanup (xfree, canon);
|
| - lookup_name = canon;
|
| - }
|
| -
|
| - add_matching_symbols_to_info (lookup_name, &info, NULL);
|
| -
|
| - if (info.result.nelts > 0)
|
| - {
|
| - if (self->canonical)
|
| - {
|
| - self->canonical->pre_expanded = 1;
|
| - if (self->user_filename)
|
| - self->canonical->addr_string
|
| - = xstrprintf ("%s:%s", self->user_filename, copy);
|
| - else
|
| - self->canonical->addr_string = xstrdup (copy);
|
| - }
|
| - return info.result;
|
| - }
|
| -
|
| - if (!have_full_symbols ()
|
| - && !have_partial_symbols ()
|
| - && !have_minimal_symbols ())
|
| - throw_error (NOT_FOUND_ERROR,
|
| - _("No symbol table is loaded. Use the \"file\" command."));
|
| - if (self->user_filename)
|
| - throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined in \"%s\"."),
|
| - copy, self->user_filename);
|
| - else
|
| - throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined."), copy);
|
| -}
|
| -
|
| -
|
|
|
|
|
| /* Now come some functions that are called from multiple places within
|
|
|