aboutsummaryrefslogtreecommitdiff
path: root/gdb/linespec.c
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2011-12-06 18:54:43 +0000
committerTom Tromey <tromey@redhat.com>2011-12-06 18:54:43 +0000
commitf8eba3c61629b3c03ac1f33853eab4d8507adb9c (patch)
tree5cac92f7145c1521976f16ddd0374861e0b967c4 /gdb/linespec.c
parent75c8c9d72cb6cdf4ccbaa5082bd7037afaf0fe8e (diff)
downloadgdb-f8eba3c61629b3c03ac1f33853eab4d8507adb9c.zip
gdb-f8eba3c61629b3c03ac1f33853eab4d8507adb9c.tar.gz
gdb-f8eba3c61629b3c03ac1f33853eab4d8507adb9c.tar.bz2
the "ambiguous linespec" series
gdb 2011-12-06 Joel Brobecker <brobecker@acacore.com> * language.h (struct language_defn): Add new component la_symbol_name_compare. * symfile.h (struct quick_symbol_functions): Update the profile of parameter "name_matcher" for the expand_symtabs_matching method. Update the documentation accordingly. * ada-lang.h (ada_name_for_lookup): Add declaration. * ada-lang.c (ada_name_for_lookup): New function, extracted out from ada_iterate_over_symbols. (ada_iterate_over_symbols): Do not encode symbol name anymore. (ada_expand_partial_symbol_name): Adjust profile. (ada_language_defn): Add value for la_symbol_name_compare field. * linespec.c: #include "ada-lang.h". (iterate_name_matcher): Add language parameter. Replace call to strcmp_iw by call to language->la_symbol_name_compare. (decode_variable): Encode COPY if current language is Ada. * dwarf2read.c (dw2_expand_symtabs_matching): Adjust profile of name_matcher parameter. Adjust call to name_matcher. * psymtab.c (expand_symtabs_matching_via_partial): Likewise. (expand_partial_symbol_names): Update profile of parameter "fun". * psymtab.h (expand_partial_symbol_names): Update profile of parameter "fun". * symtab.c (demangle_for_lookup): Update function documentation. (search_symbols_name_matches): Add language parameter. (expand_partial_symbol_name): Likewise. * c-lang.c (c_language_defn, cplus_language_defn) (asm_language_defn, minimal_language_defn): Add value for la_symbol_name_compare field. * d-lang.c (d_language_defn): Likewise. * f-lang.c (f_language_defn): Ditto. * jv-lang.c (java_language_defn): Ditto. * m2-lang.c (m2_language_defn): Ditto. * objc-lang.c (objc_language_defn): Ditto. * opencl-lang.c (opencl_language_defn): Ditto. * p-lang.c (pascal_language_defn): Ditto. * language.c (unknown_language_defn, auto_language_defn) (local_language_defn): Ditto. 2011-12-06 Tom Tromey <tromey@redhat.com> * linespec.c (iterate_over_all_matching_symtabs): Use LA_ITERATE_OVER_SYMBOLS. (lookup_prefix_sym, add_matching_symbols_to_info): Likewise. (find_function_symbols, decode_variable): Remove Ada special case. * language.h (struct language_defn) <la_iterate_over_symbols>: New field. (LA_ITERATE_OVER_SYMBOLS): New macro. * language.c (unknown_language_defn, auto_language_defn) (local_language_defn): Update. * c-lang.c (c_language_defn, cplus_language_defn) (asm_language_defn, minimal_language_defn): Update. * d-lang.c (d_language_defn): Update. * f-lang.c (f_language_defn): Update. * jv-lang.c (java_language_defn): Update. * m2-lang.c (m2_language_defn): Update. * objc-lang.c (objc_language_defn): Update. * opencl-lang.c (opencl_language_defn): Update. * p-lang.c (pascal_language_defn): Update. * ada-lang.c (ada_iterate_over_symbols): New function. (ada_language_defn): Update. 2011-12-06 Tom Tromey <tromey@redhat.com> Joel Brobecker <brobecker@acacore.com> PR breakpoints/13105, PR objc/8341, PR objc/8343, PR objc/8366, PR objc/8535, PR breakpoints/11657, PR breakpoints/11970, PR breakpoints/12023, PR breakpoints/12334, PR breakpoints/12856, PR shlibs/8929, PR shlibs/7393: * python/py-type.c (compare_maybe_null_strings): Rename from compare_strings. (check_types_equal): Update. * utils.c (compare_strings): New function. * tui/tui-winsource.c (tui_update_breakpoint_info): Update for location changes. * tracepoint.c (scope_info): Update. (trace_find_line_command): Use DECODE_LINE_FUNFIRSTLINE. * symtab.h (iterate_over_minimal_symbols) (iterate_over_some_symtabs, iterate_over_symtabs) (find_pcs_for_symtab_line, iterate_over_symbols) (demangle_for_lookup): Declare. (expand_line_sal): Remove. * symtab.c (iterate_over_some_symtabs, iterate_over_symtabs) (lookup_symtab_callback): New functions. (lookup_symtab): Rewrite. (demangle_for_lookup): New function, extract from lookup_symbol_in_language. (lookup_symbol_in_language): Use it. (iterate_over_symbols): New function. (find_line_symtab): Update. (find_pcs_for_symtab_line): New functions. (find_line_common): Add 'start' argument. (decode_line_spec): Update. Change argument to 'flags', change interpretation. (append_expanded_sal): Remove. (append_exact_match_to_sals): Remove. (expand_line_sal): Remove. * symfile.h (struct quick_symbol_functions) <lookup_symtab>: Remove. <map_symtabs_matching_filename>: New field. * stack.c (func_command): Only look in the current program space. Use DECODE_LINE_FUNFIRSTLINE. * source.c (line_info): Set pspace on sal. Check program space in the loop. Use DECODE_LINE_LIST_MODE. (select_source_symtab): Use DECODE_LINE_FUNFIRSTLINE. * solib-target.c: Remove DEF_VEC_I(CORE_ADDR). * python/python.c (gdbpy_decode_line): Update. * psymtab.c (partial_map_expand_apply): New function. (partial_map_symtabs_matching_filename): Rename from lookup_partial_symbol. Update arguments. (lookup_symtab_via_partial_symtab): Remove. (psym_functions): Update. * objc-lang.h (parse_selector, parse_method): Don't declare. (find_imps): Update. * objc-lang.c (parse_selector, parse_method): Now static. (find_methods): Change arguments. Fill in a vector of symbol names. (uniquify_strings): New function. (find_imps): Change arguments. * minsyms.c (iterate_over_minimal_symbols): New function. * linespec.h (enum decode_line_flags): New. (struct linespec_sals): New. (struct linespec_result) <canonical>: Remove. <pre_expanded, addr_string, sals>: New fields. (destroy_linespec_result, make_cleanup_destroy_linespec_result) (decode_line_full): Declare. (decode_line_1): Update. * linespec.c (struct address_entry, struct linespec_state, struct collect_info): New types. (add_sal_to_sals_basic, add_sal_to_sals, hash_address_entry) (eq_address_entry, maybe_add_address): New functions. (total_number_of_methods): Remove. (iterate_name_matcher, iterate_over_all_matching_symtabs): New functions. (find_methods): Change arguments. Don't canonicalize input. Simplify logic. (add_matching_methods, add_constructors) (build_canonical_line_spec): Remove. (filter_results, convert_results_to_lsals): New functions. (decode_line_2): Change arguments. Rewrite for new data structures. (decode_line_internal): Rename from decode_line_1. Change arguments. Add cleanups. Update for new data structures. (linespec_state_constructor, linespec_state_destructor) (decode_line_full, decode_line_1): New functions. (decode_indirect): Change arguments. Update. (locate_first_half): Use skip_spaces. (decode_objc): Change arguments. Update for new data structures. Simplify logic. (decode_compound): Change arguments. Add cleanups. Remove fallback code, replace with error. (struct decode_compound_collector): New type. (collect_one_symbol): New function. (lookup_prefix_sym): Change arguments. Update. (compare_symbol_name, add_all_symbol_names_from_pspace) (find_superclass_methods ): New functions. (find_method): Rewrite. (struct symtab_collector): New type. (add_symtabs_to_list, collect_symtabs_from_filename): New functions. (symtabs_from_filename): Change API. Rename from symtab_from_filename. (collect_function_symbols): New function. (find_function_symbols): Change API. Rename from find_function_symbol. Rewrite. (decode_all_digits): Change arguments. Rewrite. (decode_dollar): Change arguments. Use decode_variable. (decode_label): Change arguments. Rewrite. (collect_symbols): New function. (minsym_found): Change arguments. Rewrite. (check_minsym, search_minsyms_for_name) (add_matching_symbols_to_info): New function. (decode_variable): Change arguments. Iterate over all symbols. (symbol_found): Remove. (symbol_to_sal): New function. (init_linespec_result, destroy_linespec_result) (cleanup_linespec_result, make_cleanup_destroy_linespec_result): New functions. (decode_digits_list_mode, decode_digits_ordinary): New functions. * dwarf2read.c (dw2_map_expand_apply): New function. (dw2_map_symtabs_matching_filename): Rename from dw2_lookup_symtab. Change arguments. (dwarf2_gdb_index_functions): Update. * dwarf2loc.c: Remove DEF_VEC_I(CORE_ADDR). * defs.h (compare_strings): Declare. * cli/cli-cmds.c (compare_strings): Move to utils.c. (edit_command, list_command): Use DECODE_LINE_LIST_MODE. Call filter_sals. (compare_symtabs, filter_sals): New functions. * breakpoint.h (struct bp_location) <line_number, source_file>: New fields. (struct breakpoint) <line_number, source_file>: Remove. <filter>: New field. * breakpoint.c (print_breakpoint_location, init_raw_breakpoint) (momentary_breakpoint_from_master, add_location_to_breakpoint): Update for changes to locations. (init_breakpoint_sal): Add 'filter' argument. Set 'filter' on breakpoint. (create_breakpoint_sal): Add 'filter' argument. (remove_sal, expand_line_sal_maybe): Remove. (create_breakpoints_sal): Remove 'sals' argument. Handle pre-expanded sals and the filter. (parse_breakpoint_sals): Use decode_line_full. (check_fast_tracepoint_sals): Use get_sal_arch. (create_breakpoint): Create a linespec_sals. Update. (break_range_command): Use decode_line_full. Update. (until_break_command): Update. (clear_command): Update match conditions for linespec.c changes. Use DECODE_LINE_LIST_MODE. (say_where): Update for changes to locations. (bp_location_dtor): Free 'source_file'. (base_breakpoint_dtor): Free 'filter'. Don't free 'source_file'. (update_static_tracepoint): Update for changes to locations. (update_breakpoint_locations): Disable ranged breakpoint if too many locations match. Update. (addr_string_to_sals): Use decode_line_full. Resolve all sal PCs. (breakpoint_re_set_default): Don't call expand_line_sal_maybe. (decode_line_spec_1): Update. Change argument name to 'flags', change interpretation. * block.h (block_containing_function): Declare. * block.c (block_containing_function): New function. * skip.c (skip_function_command): Update. (skip_re_set): Update. * infcmd.c (jump_command): Use DECODE_LINE_FUNFIRSTLINE. * mi/mi-main.c (mi_cmd_trace_find): Use DECODE_LINE_FUNFIRSTLINE. * NEWS: Add entry. 2011-12-06 Tom Tromey <tromey@redhat.com> * elfread.c (elf_gnu_ifunc_resolver_return_stop): Allow breakpoint's pspace to be NULL. * breakpoint.h (struct breakpoint) <pspace>: Update comment. * breakpoint.c (init_raw_breakpoint): Conditionally set breakpoint's pspace. (init_breakpoint_sal): Don't set breakpoint's pspace. (prepare_re_set_context): Conditionally switch program space. (addr_string_to_sals): Check executing_startup on location's program space. 2011-12-06 Tom Tromey <tromey@redhat.com> * breakpoint.h (enum enable_state) <bp_startup_disabled>: Remove. * breakpoint.c (should_be_inserted): Explicitly check if program space is executing startup. (describe_other_breakpoints): Update. (disable_breakpoints_before_startup): Change executing_startup earlier. Remove loop. (enable_breakpoints_after_startup): Likewise. (init_breakpoint_sal): Don't use bp_startup_disabled. (create_breakpoint): Don't use bp_startup_disabled. (update_global_location_list): Use should_be_inserted. (bkpt_re_set): Update. gdb/testsuite 2011-12-06 Joel Brobecker <brobecker@acacore.com> * gdb.ada/fullname_bp.exp: Add tests for other valid linespecs involving a fully qualified function name. 2011-12-06 Tom Tromey <tromey@redhat.com> * gdb.ada/homonym.exp: Add three breakpoint tests. 2011-12-06 Tom Tromey <tromey@redhat.com> * gdb.base/solib-weak.exp (do_test): Remove kfail. * gdb.trace/tracecmd.exp: Disable pending breakpoints earlier. * gdb.objc/objcdecode.exp: Update for output changes. * gdb.linespec/linespec.exp: New file. * gdb.linespec/lspec.cc: New file. * gdb.linespec/lspec.h: New file. * gdb.linespec/body.h: New file. * gdb.linespec/base/two/thefile.cc: New file. * gdb.linespec/base/one/thefile.cc: New file. * gdb.linespec/Makefile.in: New file. * gdb.cp/templates.exp (test_template_breakpoints): Update for output changes. * gdb.cp/re-set-overloaded.exp: Remove kfail. * gdb.cp/ovldbreak.exp: Update for output changes. "all" test now makes one breakpoint. * gdb.cp/method2.exp (test_break): Update for output changes. * gdb.cp/mb-templates.exp: Update for output changes. * gdb.cp/mb-inline.exp: Update for output changes. * gdb.cp/mb-ctor.exp: Update for output changes. * gdb.cp/ovsrch.exp: Use fully-qualified names. * gdb.base/solib-symbol.exp: Run to main later. Breakpoint now has multiple matches. * gdb.base/sepdebug.exp: Disable pending breakpoints. Update for error message change. * gdb.base/list.exp (test_list_filename_and_number): Update for error message change. * gdb.base/break.exp: Disable pending breakpoints. Update for output changes. * configure.ac: Add gdb.linespec. * configure: Rebuild. * Makefile.in (ALL_SUBDIRS): Add gdb.linespec. gdb/doc 2011-12-06 Tom Tromey <tromey@redhat.com> * gdb.texinfo (Set Breaks): Update for new behavior.
Diffstat (limited to 'gdb/linespec.c')
-rw-r--r--gdb/linespec.c2531
1 files changed, 1596 insertions, 935 deletions
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 64ba837..e6e863d 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -44,109 +44,252 @@
#include <ctype.h>
#include "cli/cli-utils.h"
#include "filenames.h"
+#include "ada-lang.h"
+
+typedef struct symtab *symtab_p;
+DEF_VEC_P (symtab_p);
+
+typedef struct symbol *symbolp;
+DEF_VEC_P (symbolp);
+
+typedef struct type *typep;
+DEF_VEC_P (typep);
+
+/* An address entry is used to ensure that any given location is only
+ added to the result a single time. It holds an address and the
+ program space from which the address came. */
+
+struct address_entry
+{
+ struct program_space *pspace;
+ CORE_ADDR addr;
+};
+
+/* 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 program space as seen when the module was entered. */
+ struct program_space *program_space;
+
+ /* The default symtab to use, if no other symtab is specified. */
+ struct symtab *default_symtab;
+
+ /* 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;
+
+ /* Nonzero if we are running in 'list' mode; see decode_line_list. */
+ int list_mode;
+
+ /* The 'canonical' value passed to decode_line_full, or NULL. */
+ struct linespec_result *canonical;
+
+ /* Canonical strings that mirror the symtabs_and_lines result. */
+ char **canonical_names;
+
+ /* This is a set of address_entry objects which is used to prevent
+ duplicate symbols from being entered into the result. */
+ htab_t addr_set;
+};
+
+/* This is a helper object that is used when collecting symbols into a
+ result. */
+
+struct collect_info
+{
+ /* The linespec object in use. */
+ struct linespec_state *state;
+
+ /* The result being accumulated. */
+ struct symtabs_and_lines result;
+
+ /* The current objfile; used only by the minimal symbol code. */
+ struct objfile *objfile;
+};
/* Prototypes for local functions. */
static void initialize_defaults (struct symtab **default_symtab,
int *default_line);
-static struct symtabs_and_lines decode_indirect (char **argptr);
+static struct symtabs_and_lines decode_indirect (struct linespec_state *self,
+ char **argptr);
static char *locate_first_half (char **argptr, int *is_quote_enclosed);
-static struct symtabs_and_lines decode_objc (char **argptr,
- int funfirstline,
- struct symtab *file_symtab,
- struct linespec_result *canonical,
- char *saved_arg);
+static struct symtabs_and_lines decode_objc (struct linespec_state *self,
+ char **argptr);
-static struct symtabs_and_lines decode_compound (char **argptr,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
+static struct symtabs_and_lines decode_compound (struct linespec_state *self,
+ char **argptr,
char *saved_arg,
char *p);
-static struct symbol *lookup_prefix_sym (char **argptr, char *p,
- struct symtab *);
+static VEC (symbolp) *lookup_prefix_sym (char **argptr, char *p,
+ VEC (symtab_p) *,
+ char **);
-static struct symtabs_and_lines find_method (int funfirstline,
- struct linespec_result *canonical,
+static struct symtabs_and_lines find_method (struct linespec_state *self,
char *saved_arg,
char *copy,
- struct type *t,
- struct symbol *sym_class,
- struct symtab *);
+ const char *class_name,
+ VEC (symbolp) *sym_classes);
static void cplusplus_error (const char *name, const char *fmt, ...)
ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
-static int total_number_of_methods (struct type *type);
+static char *find_toplevel_char (char *s, char c);
-static int find_methods (struct type *, char *,
- enum language, struct symbol **, struct symtab *);
+static int is_objc_method_format (const char *s);
-static int add_matching_methods (int method_counter, struct type *t,
- enum language language,
- struct symbol **sym_arr);
+static VEC (symtab_p) *symtabs_from_filename (char **argptr,
+ char *p, int is_quote_enclosed,
+ char **user_filename);
-static int add_constructors (int method_counter, struct type *t,
- enum language language,
- struct symbol **sym_arr);
+static VEC (symbolp) *find_function_symbols (char **argptr, char *p,
+ int is_quote_enclosed,
+ char **user_function);
-static void build_canonical_line_spec (struct symtab_and_line *,
- char *, struct linespec_result *);
+static struct symtabs_and_lines decode_all_digits (struct linespec_state *self,
+ char **argptr,
+ char *q);
-static char *find_toplevel_char (char *s, char c);
+static struct symtabs_and_lines decode_dollar (struct linespec_state *self,
+ char *copy);
-static int is_objc_method_format (const char *s);
+static int decode_label (struct linespec_state *self,
+ VEC (symbolp) *function_symbols,
+ char *copy,
+ struct symtabs_and_lines *result);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static struct symtabs_and_lines decode_variable (struct linespec_state *self,
+ char *copy);
-static struct symtab *symtab_from_filename (char **argptr,
- char *p, int is_quote_enclosed);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+static void add_matching_symbols_to_info (const char *name,
+ struct collect_info *info,
+ struct program_space *pspace);
-static struct
-symtabs_and_lines decode_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+static void add_all_symbol_names_from_pspace (struct collect_info *info,
+ struct program_space *pspace,
+ VEC (const_char_ptr) *names);
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Helper functions. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+/* Add SAL to SALS. */
-static struct symtabs_and_lines decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+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 struct
-symtabs_and_lines symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+/* 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 struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+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);
-/* Helper functions. */
+ 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
+ && 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);
+ }
+
+ 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;
+
+ return iterative_hash_object (*aep, 0);
+}
+
+/* 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;
+}
/* Issue a helpful hint on using the command completion feature on
single quoted demangled C++ symbols as part of the completion
@@ -181,26 +324,66 @@ cplusplus_error (const char *name, const char *fmt, ...)
throw_error (NOT_FOUND_ERROR, "%s", message);
}
-/* Return the number of methods described for TYPE, including the
- methods from types it derives from. This can't be done in the symbol
- reader because the type of the baseclass might still be stubbed
- when the definition of the derived class is parsed. */
+/* A helper for iterate_over_all_matching_symtabs that is passed as a
+ callback to the expand_symtabs_matching method. */
static int
-total_number_of_methods (struct type *type)
+iterate_name_matcher (const struct language_defn *language,
+ const char *name, void *d)
{
- int n;
- int count;
+ const char **dname = d;
- CHECK_TYPEDEF (type);
- if (! HAVE_CPLUS_STRUCT (type))
- return 0;
- count = TYPE_NFN_FIELDS_TOTAL (type);
+ if (language->la_symbol_name_compare (name, *dname) == 0)
+ return 1;
+ return 0;
+}
+
+/* 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. */
+
+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)
+{
+ struct objfile *objfile;
+ struct program_space *pspace;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ 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,
+ &name);
- return count;
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -227,40 +410,24 @@ get_search_block (struct symtab *symtab)
return block;
}
-/* Recursive helper function for decode_line_1.
- Look for methods named NAME in type T.
- Return number of matches.
- Put matches in SYM_ARR, which should have been allocated with
- a size of total_number_of_methods (T) * sizeof (struct symbol *).
- Note that this function is g++ specific. */
+/* 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. */
-static int
-find_methods (struct type *t, char *name, enum language language,
- struct symbol **sym_arr, struct symtab *file_symtab)
+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);
- struct cleanup *cleanup;
char *canon;
- /* NAME is typed by the user: it needs to be canonicalized before
- passing to lookup_symbol. */
- canon = cp_canonicalize_string_no_typedefs (name);
- if (canon != NULL)
- {
- name = canon;
- cleanup = make_cleanup (xfree, name);
- }
- else
- cleanup = make_cleanup (null_cleanup, NULL);
-
/* 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
- && (lookup_symbol_in_language (class_name, get_search_block (file_symtab),
- STRUCT_DOMAIN, language, (int *) NULL)))
+ if (class_name)
{
int method_counter;
int name_len = strlen (name);
@@ -288,181 +455,32 @@ find_methods (struct type *t, char *name, enum language language,
method_name = dem_opname;
}
- if (strcmp_iw (name, method_name) == 0)
- /* Find all the overloaded methods with that name. */
- i1 += add_matching_methods (method_counter, t, language,
- sym_arr + i1);
- else if (strncmp (class_name, name, name_len) == 0
- && (class_name[name_len] == '\0'
- || class_name[name_len] == '<'))
- i1 += add_constructors (method_counter, t, language,
- sym_arr + i1);
- }
- }
-
- /* Only search baseclasses if there is no match yet, since names in
- derived classes override those in baseclasses.
-
- FIXME: The above is not true; it is only true of member functions
- if they have the same number of arguments (??? - section 13.1 of the
- ARM says the function members are not in the same scope but doesn't
- really spell out the rules in a way I understand. In any case, if
- the number of arguments differ this is a case in which we can overload
- rather than hiding without any problem, and gcc 2.4.5 does overload
- rather than hiding in this case). */
-
- if (i1 == 0)
- for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
- i1 += find_methods (TYPE_BASECLASS (t, ibase), name,
- language, sym_arr + i1, file_symtab);
-
- do_cleanups (cleanup);
- return i1;
-}
-
-/* Add the symbols associated to methods of the class whose type is T
- and whose name matches the method indexed by METHOD_COUNTER in the
- array SYM_ARR. Return the number of methods added. */
-
-static int
-add_matching_methods (int method_counter, struct type *t,
- enum language language, struct symbol **sym_arr)
-{
- int field_counter;
- int i1 = 0;
-
- for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
- field_counter >= 0;
- --field_counter)
- {
- struct fn_field *f;
- const char *phys_name;
-
- f = TYPE_FN_FIELDLIST1 (t, method_counter);
+ if (strcmp_iw (method_name, name) == 0)
+ {
+ int field_counter;
- if (TYPE_FN_FIELD_STUB (f, field_counter))
- {
- char *tmp_name, *tmp2;
-
- tmp_name = gdb_mangle_name (t,
- method_counter,
- field_counter);
- tmp2 = alloca (strlen (tmp_name) + 1);
- strcpy (tmp2, tmp_name);
- xfree (tmp_name);
- phys_name = tmp2;
- }
- else
- phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
-
- sym_arr[i1] = lookup_symbol_in_language (phys_name,
- NULL, VAR_DOMAIN,
- language,
- (int *) NULL);
- if (sym_arr[i1])
- i1++;
- else
- {
- /* This error message gets printed, but the method
- still seems to be found.
- fputs_filtered("(Cannot find method ", gdb_stdout);
- fprintf_symbol_filtered (gdb_stdout, phys_name,
- language_cplus,
- DMGL_PARAMS | DMGL_ANSI);
- fputs_filtered(" - possibly inlined.)\n", gdb_stdout);
- */
+ for (field_counter = (TYPE_FN_FIELDLIST_LENGTH (t, method_counter)
+ - 1);
+ field_counter >= 0;
+ --field_counter)
+ {
+ struct fn_field *f;
+ const char *phys_name;
+
+ f = TYPE_FN_FIELDLIST1 (t, method_counter);
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ continue;
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ VEC_safe_push (const_char_ptr, *result_names, phys_name);
+ }
+ }
}
}
- return i1;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-/* Add the symbols associated to constructors of the class whose type
- is CLASS_TYPE and which are indexed by by METHOD_COUNTER to the
- array SYM_ARR. Return the number of methods added. */
-
-static int
-add_constructors (int method_counter, struct type *t,
- enum language language, struct symbol **sym_arr)
-{
- int field_counter;
- int i1 = 0;
-
- /* For GCC 3.x and stabs, constructors and destructors
- have names like __base_ctor and __complete_dtor.
- Check the physname for now if we're looking for a
- constructor. */
- for (field_counter
- = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
- field_counter >= 0;
- --field_counter)
- {
- struct fn_field *f;
- const char *phys_name;
-
- f = TYPE_FN_FIELDLIST1 (t, method_counter);
-
- /* GCC 3.x will never produce stabs stub methods, so
- we don't need to handle this case. */
- if (TYPE_FN_FIELD_STUB (f, field_counter))
- continue;
- phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
- if (! is_constructor_name (phys_name))
- continue;
-
- /* If this method is actually defined, include it in the
- list. */
- sym_arr[i1] = lookup_symbol_in_language (phys_name,
- NULL, VAR_DOMAIN,
- language,
- (int *) NULL);
- if (sym_arr[i1])
- i1++;
- }
-
- return i1;
-}
-
-/* Helper function for decode_line_1.
- Build a canonical line spec in CANONICAL if it is non-NULL and if
- the SAL has a symtab.
- If SYMNAME is non-NULL the canonical line spec is `filename:symname'.
- If SYMNAME is NULL the line number from SAL is used and the canonical
- line spec is `filename:linenum'. */
-
-static void
-build_canonical_line_spec (struct symtab_and_line *sal, char *symname,
- struct linespec_result *canonical)
-{
- char **canonical_arr;
- char *canonical_name;
- char *filename;
- struct symtab *s = sal->symtab;
-
- if (s == (struct symtab *) NULL
- || s->filename == (char *) NULL
- || canonical == NULL)
- return;
-
- canonical_arr = (char **) xmalloc (sizeof (char *));
- canonical->canonical = canonical_arr;
-
- filename = s->filename;
- if (symname != NULL)
- {
- canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
- sprintf (canonical_name, "%s:%s", filename, symname);
- }
- else
- {
- canonical_name = xmalloc (strlen (filename) + 30);
- sprintf (canonical_name, "%s:%d", filename, sal->line);
- }
- canonical_arr[0] = canonical_name;
-}
-
-
-
/* Find an instance of the character C in the string S that is outside
of all parenthesis pairs, single-quoted strings, and double-quoted
strings. Also, ignore the char within a template name, like a ','
@@ -518,147 +536,154 @@ is_objc_method_format (const char *s)
return 0;
}
-/* Given a list of NELTS symbols in SYM_ARR, return a list of lines to
- operate on (ask user if necessary).
- If CANONICAL is non-NULL return a corresponding array of mangled names
- as canonical line specs there. */
+/* Given FILTERS, a list of canonical names, filter the sals in RESULT
+ and store the result in SELF->CANONICAL. */
-static struct symtabs_and_lines
-decode_line_2 (struct symbol *sym_arr[], int nelts, int funfirstline,
- struct linespec_result *canonical)
+static void
+filter_results (struct linespec_state *self,
+ struct symtabs_and_lines *result,
+ VEC (const_char_ptr) *filters)
+{
+ int i;
+ const char *name;
+
+ for (i = 0; VEC_iterate (const_char_ptr, filters, i, name); ++i)
+ {
+ struct linespec_sals lsal;
+ int j;
+
+ memset (&lsal, 0, sizeof (lsal));
+
+ for (j = 0; j < result->nelts; ++j)
+ {
+ if (strcmp (name, self->canonical_names[j]) == 0)
+ add_sal_to_sals_basic (&lsal.sals, &result->sals[j]);
+ }
+
+ if (lsal.sals.nelts > 0)
+ {
+ lsal.canonical = xstrdup (name);
+ VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+ }
+ }
+
+ self->canonical->pre_expanded = 0;
+}
+
+/* Store RESULT into SELF->CANONICAL. */
+
+static void
+convert_results_to_lsals (struct linespec_state *self,
+ struct symtabs_and_lines *result)
+{
+ struct linespec_sals lsal;
+
+ lsal.canonical = NULL;
+ lsal.sals = *result;
+ VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+}
+
+/* Handle multiple results in RESULT depending on SELECT_MODE. This
+ will either return normally, throw an exception on multiple
+ results, or present a menu to the user. On return, the SALS vector
+ in SELF->CANONICAL is set up properly. */
+
+static void
+decode_line_2 (struct linespec_state *self,
+ struct symtabs_and_lines *result,
+ const char *select_mode)
{
- struct symtabs_and_lines values, return_values;
- char *args, *arg1;
+ const char *iter;
+ char *args, *prompt;
int i;
- char *prompt;
- char *symname;
struct cleanup *old_chain;
- char **canonical_arr = (char **) NULL;
- const char *select_mode = multiple_symbols_select_mode ();
+ VEC (const_char_ptr) *item_names = NULL, *filters = NULL;
+ struct get_number_or_range_state state;
- if (select_mode == multiple_symbols_cancel)
- error (_("canceled because the command is ambiguous\n"
- "See set/show multiple-symbol."));
-
- values.sals = (struct symtab_and_line *)
- alloca (nelts * sizeof (struct symtab_and_line));
- return_values.sals = (struct symtab_and_line *)
- xmalloc (nelts * sizeof (struct symtab_and_line));
- old_chain = make_cleanup (xfree, return_values.sals);
+ gdb_assert (select_mode != multiple_symbols_all);
+ gdb_assert (self->canonical != NULL);
- if (canonical)
+ old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &item_names);
+ make_cleanup (VEC_cleanup (const_char_ptr), &filters);
+ for (i = 0; i < result->nelts; ++i)
{
- canonical_arr = (char **) xmalloc (nelts * sizeof (char *));
- make_cleanup (xfree, canonical_arr);
- memset (canonical_arr, 0, nelts * sizeof (char *));
- canonical->canonical = canonical_arr;
+ int j, found = 0;
+ const char *iter;
+
+ gdb_assert (self->canonical_names[i] != NULL);
+ for (j = 0; VEC_iterate (const_char_ptr, item_names, j, iter); ++j)
+ {
+ if (strcmp (iter, self->canonical_names[i]) == 0)
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ VEC_safe_push (const_char_ptr, item_names, self->canonical_names[i]);
}
- i = 0;
- while (i < nelts)
+ if (select_mode == multiple_symbols_cancel
+ && VEC_length (const_char_ptr, item_names) > 1)
+ error (_("canceled because the command is ambiguous\n"
+ "See set/show multiple-symbol."));
+
+ if (select_mode == multiple_symbols_all
+ || VEC_length (const_char_ptr, item_names) == 1)
{
- init_sal (&return_values.sals[i]); /* Initialize to zeroes. */
- init_sal (&values.sals[i]);
- if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
- values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline);
- i++;
+ do_cleanups (old_chain);
+ convert_results_to_lsals (self, result);
+ return;
}
- /* If select_mode is "all", then do not print the multiple-choice
- menu and act as if the user had chosen choice "1" (all). */
- if (select_mode == multiple_symbols_all
- || ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
- args = "1";
- else
+ 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)
{
- i = 0;
- printf_unfiltered (_("[0] cancel\n[1] all\n"));
- while (i < nelts)
- {
- if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
- {
- if (values.sals[i].symtab)
- printf_unfiltered ("[%d] %s at %s:%d\n",
- (i + 2),
- SYMBOL_PRINT_NAME (sym_arr[i]),
- values.sals[i].symtab->filename,
- values.sals[i].line);
- else
- printf_unfiltered (_("[%d] %s at ?FILE:%d [No symtab? "
- "Probably broken debug info...]\n"),
- (i + 2),
- SYMBOL_PRINT_NAME (sym_arr[i]),
- values.sals[i].line);
-
- }
- else
- printf_unfiltered (_("?HERE\n"));
- i++;
- }
-
- prompt = getenv ("PS2");
- if (prompt == NULL)
- {
- prompt = "> ";
- }
- args = command_line_input (prompt, 0, "overload-choice");
+ prompt = "> ";
}
+ args = command_line_input (prompt, 0, "overload-choice");
if (args == 0 || *args == 0)
error_no_arg (_("one or more choice numbers"));
- i = 0;
- while (*args)
+ init_number_or_range (&state, args);
+ while (!state.finished)
{
int num;
- arg1 = args;
- while (*arg1 >= '0' && *arg1 <= '9')
- arg1++;
- if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
- error (_("Arguments must be choice numbers."));
-
- num = atoi (args);
+ num = get_number_or_range (&state);
if (num == 0)
error (_("canceled"));
else if (num == 1)
{
- if (canonical_arr)
- {
- for (i = 0; i < nelts; i++)
- {
- if (canonical_arr[i] == NULL)
- {
- symname = SYMBOL_LINKAGE_NAME (sym_arr[i]);
- canonical_arr[i] = xstrdup (symname);
- }
- }
- }
- memcpy (return_values.sals, values.sals,
- (nelts * sizeof (struct symtab_and_line)));
- return_values.nelts = nelts;
- discard_cleanups (old_chain);
- return return_values;
+ /* 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 (num >= nelts + 2)
- {
- printf_unfiltered (_("No choice number %d.\n"), num);
- }
+ num -= 2;
+ if (num >= VEC_length (const_char_ptr, item_names))
+ printf_unfiltered (_("No choice number %d.\n"), num);
else
{
- num -= 2;
- if (values.sals[num].pc)
+ const char *elt = VEC_index (const_char_ptr, item_names, num);
+
+ if (elt != NULL)
{
- if (canonical_arr)
- {
- symname = SYMBOL_LINKAGE_NAME (sym_arr[num]);
- make_cleanup (xfree, symname);
- canonical_arr[i] = xstrdup (symname);
- }
- return_values.sals[i++] = values.sals[num];
- values.sals[num].pc = 0;
+ VEC_safe_push (const_char_ptr, filters, elt);
+ VEC_replace (const_char_ptr, item_names, num, NULL);
}
else
{
@@ -666,14 +691,10 @@ decode_line_2 (struct symbol *sym_arr[], int nelts, int funfirstline,
num);
}
}
-
- args = arg1;
- while (*args == ' ' || *args == '\t')
- args++;
}
- return_values.nelts = i;
- discard_cleanups (old_chain);
- return return_values;
+
+ filter_results (self, result, filters);
+ do_cleanups (old_chain);
}
/* Valid delimiters for linespec keywords "if", "thread" or "task". */
@@ -813,13 +834,10 @@ keep_name_info (char *p, int on_boundary)
can use as appropriate instead of make_symbol_completion_list. */
struct symtabs_and_lines
-decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
- int default_line, struct linespec_result *canonical)
+decode_line_internal (struct linespec_state *self, char **argptr)
{
char *p;
char *q;
- /* If a file name is specified, this is its symtab. */
- struct symtab *file_symtab = NULL;
char *copy;
/* This says whether or not something in *ARGPTR is quoted with
@@ -836,21 +854,26 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
/* The "first half" of the linespec. */
char *first_half;
- /* If we are parsing `function:label', this holds the symbol for the
- function. */
- struct symbol *function_symbol = NULL;
- /* If FUNCTION_SYMBOL is not NULL, then this is the exception that
+ /* 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. */
volatile struct gdb_exception file_exception;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+
/* Defaults have defaults. */
- initialize_defaults (&default_symtab, &default_line);
+ initialize_defaults (&self->default_symtab, &self->default_line);
/* See if arg is *PC. */
if (**argptr == '*')
- return decode_indirect (argptr);
+ {
+ do_cleanups (cleanup);
+ return decode_indirect (self, argptr);
+ }
is_quoted = (strchr (get_gdb_completer_quote_characters (),
**argptr) != NULL);
@@ -877,7 +900,14 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
symtab and strip the filename from ARGPTR. */
TRY_CATCH (file_exception, RETURN_MASK_ERROR)
{
- file_symtab = symtab_from_filename (argptr, p, is_quote_enclosed);
+ 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)
@@ -903,10 +933,12 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
{
struct symtabs_and_lines values;
- values = decode_objc (argptr, funfirstline, file_symtab,
- canonical, saved_arg);
+ values = decode_objc (self, argptr);
if (values.sals != NULL)
- return values;
+ {
+ do_cleanups (cleanup);
+ return values;
+ }
}
/* Does it look like there actually were two parts? */
@@ -934,14 +966,16 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
- values = decode_compound (argptr, funfirstline, canonical,
- file_symtab, saved_arg, p);
+ values = decode_compound (self, argptr, saved_arg, p);
}
if ((is_quoted || is_squote_enclosed) && **argptr == '\'')
*argptr = *argptr + 1;
if (ex.reason >= 0)
- return values;
+ {
+ do_cleanups (cleanup);
+ return values;
+ }
if (ex.error != NOT_FOUND_ERROR)
throw_exception (ex);
@@ -954,12 +988,16 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
then check whether we were really given `function:label'. */
if (file_exception.reason < 0)
{
- function_symbol = find_function_symbol (argptr, p,
- is_quote_enclosed);
+ function_symbols = find_function_symbols (argptr, p,
+ is_quote_enclosed,
+ &self->user_function);
+
/* If we did not find a function, re-throw the original
exception. */
- if (!function_symbol)
+ if (!function_symbols)
throw_exception (file_exception);
+
+ make_cleanup (VEC_cleanup (symbolp), &function_symbols);
}
/* Check for single quotes on the non-filename part. */
@@ -974,9 +1012,10 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
}
}
- /* file_symtab is specified file's symtab, or 0 if no file specified.
- If we are parsing `function:symbol', then FUNCTION_SYMBOL is the
- function before the `:'.
+ /* 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. */
/* If the filename was quoted, we must re-check the quotation. */
@@ -999,10 +1038,15 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
q++;
if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',')
- && function_symbol == NULL)
- /* We found a token consisting of all digits -- at least one digit. */
- return decode_all_digits (argptr, default_symtab, default_line,
- canonical, file_symtab, q);
+ && function_symbols == NULL)
+ {
+ struct symtabs_and_lines values;
+
+ /* We found a token consisting of all digits -- at least one digit. */
+ values = decode_all_digits (self, argptr, q);
+ do_cleanups (cleanup);
+ return values;
+ }
/* Arg token is not digits => try it as a variable name
Find the next token (everything up to end or next whitespace). */
@@ -1042,61 +1086,181 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
}
else if (is_quoted || is_squote_enclosed)
copy[p - *argptr - 1] = '\0';
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
+
+ *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. */
- if (*copy == '$' && function_symbol == NULL)
- return decode_dollar (copy, funfirstline, default_symtab,
- canonical, file_symtab);
+ if (*copy == '$' && function_symbols == NULL)
+ {
+ struct symtabs_and_lines values;
+
+ values = decode_dollar (self, copy);
+ do_cleanups (cleanup);
+ return values;
+ }
/* 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 (!file_symtab)
+ 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 (function_symbol, copy, canonical, &label_result))
- return label_result;
+ if (decode_label (self, function_symbols, copy, &label_result))
+ {
+ do_cleanups (cleanup);
+ return label_result;
+ }
}
- if (function_symbol)
+ if (function_symbols)
throw_exception (file_exception);
/* Look up that token as a variable.
If file specified, use that file's per-file block to start with. */
- return decode_variable (copy, funfirstline, canonical, file_symtab);
+ {
+ struct symtabs_and_lines values;
+
+ values = decode_variable (self, copy);
+ do_cleanups (cleanup);
+ return values;
+ }
}
-
+/* A constructor for linespec_state. */
+
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int flags,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = (flags & DECODE_LINE_FUNFIRSTLINE) ? 1 : 0;
+ self->list_mode = (flags & DECODE_LINE_LIST_MODE) ? 1 : 0;
+ self->default_symtab = default_symtab;
+ self->default_line = default_line;
+ self->canonical = canonical;
+ self->program_space = current_program_space;
+ self->addr_set = htab_create_alloc (10, hash_address_entry, eq_address_entry,
+ xfree, xcalloc, xfree);
+}
+
+/* A destructor for linespec_state. */
+
+static void
+linespec_state_destructor (void *arg)
+{
+ 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);
+}
+
+/* See linespec.h. */
+
+void
+decode_line_full (char **argptr, int flags,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ 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;
+
+ gdb_assert (canonical != NULL);
+ /* The filter only makes sense for 'all'. */
+ gdb_assert (filter == NULL || select_mode == multiple_symbols_all);
+ gdb_assert (select_mode == NULL
+ || select_mode == multiple_symbols_all
+ || select_mode == multiple_symbols_ask
+ || 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);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+
+ gdb_assert (result.nelts == 1 || canonical->pre_expanded);
+ gdb_assert (canonical->addr_string != NULL);
+ canonical->pre_expanded = 1;
+
+ /* Fill in the missing canonical names. */
+ if (result.nelts > 0)
+ {
+ int i;
-/* Now, more helper functions for decode_line_1. Some conventions
- that these functions follow:
-
- Decode_line_1 typically passes along some of its arguments or local
- variables to the subfunctions. It passes the variables by
- reference if they are modified by the subfunction, and by value
- otherwise.
-
- Some of the functions have side effects that don't arise from
- variables that are passed by reference. In particular, if a
- function is passed ARGPTR as an argument, it modifies what ARGPTR
- points to; typically, it advances *ARGPTR past whatever substring
- it has just looked at. (If it doesn't modify *ARGPTR, then the
- function gets passed *ARGPTR instead, which is then called ARG.)
- Also, functions that return a struct symtabs_and_lines may modify
- CANONICAL, as in the description of decode_line_1.
-
- If a function returns a struct symtabs_and_lines, then that struct
- will immediately make its way up the call chain to be returned by
- decode_line_1. In particular, all of the functions decode_XXX
- calculate the appropriate struct symtabs_and_lines, under the
- assumption that their argument is of the form XXX. */
+ 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 (select_mode == NULL)
+ {
+ if (ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
+ select_mode = multiple_symbols_all;
+ else
+ select_mode = multiple_symbols_select_mode ();
+ }
+
+ if (select_mode == multiple_symbols_all)
+ {
+ if (filter != NULL)
+ {
+ make_cleanup (VEC_cleanup (const_char_ptr), &filters);
+ VEC_safe_push (const_char_ptr, filters, filter);
+ filter_results (&state, &result, filters);
+ }
+ else
+ convert_results_to_lsals (&state, &result);
+ }
+ else
+ decode_line_2 (&state, &result, select_mode);
+
+ do_cleanups (cleanups);
+}
+
+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;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, flags,
+ default_symtab, default_line, NULL);
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+
/* First, some functions to initialize stuff at the beggining of the
function. */
@@ -1122,11 +1286,18 @@ initialize_defaults (struct symtab **default_symtab, int *default_line)
/* Decode arg of the form *PC. */
static struct symtabs_and_lines
-decode_indirect (char **argptr)
+decode_indirect (struct linespec_state *self, char **argptr)
{
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));
@@ -1139,6 +1310,9 @@ decode_indirect (char **argptr)
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;
}
@@ -1246,8 +1420,7 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
break;
}
}
- while (p[0] == ' ' || p[0] == '\t')
- p++;
+ p = skip_spaces (p);
/* If the closing double quote was left at the end, remove it. */
if (*is_quote_enclosed)
@@ -1275,94 +1448,52 @@ locate_first_half (char **argptr, int *is_quote_enclosed)
than one method that could represent the selector, then use some of
the existing C++ code to let the user choose one. */
-struct symtabs_and_lines
-decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
- struct linespec_result *canonical, char *saved_arg)
+static struct symtabs_and_lines
+decode_objc (struct linespec_state *self, char **argptr)
{
- struct symtabs_and_lines values;
- struct symbol **sym_arr = NULL;
- struct symbol *sym = NULL;
- struct block *block = NULL;
- unsigned i1 = 0;
- unsigned i2 = 0;
+ struct collect_info info;
+ VEC (const_char_ptr) *symbol_names = NULL;
+ 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.objfile = NULL;
+
+ new_argptr = find_imps (*argptr, &symbol_names);
+ if (VEC_empty (const_char_ptr, symbol_names))
+ {
+ do_cleanups (cleanup);
+ return info.result;
+ }
- values.sals = NULL;
- values.nelts = 0;
+ add_all_symbol_names_from_pspace (&info, NULL, symbol_names);
- find_imps (file_symtab, get_search_block (file_symtab), *argptr,
- NULL, &i1, &i2);
-
- if (i1 > 0)
+ if (info.result.nelts > 0)
{
- sym_arr = (struct symbol **)
- alloca ((i1 + 1) * sizeof (struct symbol *));
- sym_arr[i1] = NULL;
+ char *saved_arg;
- *argptr = find_imps (file_symtab, block, *argptr, sym_arr, &i1, &i2);
- }
+ saved_arg = alloca (new_argptr - *argptr + 1);
+ memcpy (saved_arg, *argptr, new_argptr - *argptr);
+ saved_arg[new_argptr - *argptr] = '\0';
- /* i1 now represents the TOTAL number of matches found.
- i2 represents how many HIGH-LEVEL (struct symbol) matches,
- which will come first in the sym_arr array. Any low-level
- (minimal_symbol) matches will follow those. */
-
- if (i1 == 1)
- {
- if (i2 > 0)
- {
- /* Already a struct symbol. */
- sym = sym_arr[0];
- }
- else
- {
- sym = find_pc_function (SYMBOL_VALUE_ADDRESS (sym_arr[0]));
- if ((sym != NULL) && strcmp (SYMBOL_LINKAGE_NAME (sym_arr[0]),
- SYMBOL_LINKAGE_NAME (sym)) != 0)
- {
- warning (_("debugging symbol \"%s\" does "
- "not match selector; ignoring"),
- SYMBOL_LINKAGE_NAME (sym));
- sym = NULL;
- }
- }
-
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
-
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- /* Canonicalize this, so it remains resolved for dylib loads. */
- values.sals[0] = find_function_start_sal (sym, funfirstline);
- build_canonical_line_spec (values.sals,
- SYMBOL_NATURAL_NAME (sym), canonical);
- }
- else
+ if (self->canonical)
{
- /* The only match was a non-debuggable symbol, which might point
- to a function descriptor; resolve it to the actual code address
- instead. */
- struct minimal_symbol *msymbol = (struct minimal_symbol *)sym_arr[0];
- struct objfile *objfile = msymbol_objfile (msymbol);
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
-
- pc = gdbarch_convert_from_func_ptr_addr (gdbarch, pc,
- &current_target);
-
- init_sal (&values.sals[0]);
- values.sals[0].pc = pc;
+ 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);
}
- return values;
}
- if (i1 > 1)
- {
- /* More than one match. The user must choose one or more. */
- return decode_line_2 (sym_arr, i2, funfirstline, canonical);
- }
+ *argptr = new_argptr;
- return values;
+ do_cleanups (cleanup);
+ return info.result;
}
/* This handles C++ and Java compound data structures. P should point
@@ -1371,20 +1502,18 @@ decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
pointing to "AAA::inA::fun" and P pointing to "::inA::fun". */
static struct symtabs_and_lines
-decode_compound (char **argptr, int funfirstline,
- struct linespec_result *canonical, struct symtab *file_symtab,
- char *the_real_saved_arg, char *p)
+decode_compound (struct linespec_state *self,
+ char **argptr, char *the_real_saved_arg, char *p)
{
struct symtabs_and_lines values;
- char *p2, *name, *canon;
+ char *p2;
char *saved_arg2 = *argptr;
char *temp_end;
struct symbol *sym;
char *copy;
- struct symbol *sym_class;
- struct type *t;
- char *saved_arg;
- struct cleanup *cleanup;
+ 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. */
@@ -1419,8 +1548,7 @@ decode_compound (char **argptr, int funfirstline,
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.
- We just look up AAA::inA::fun with lookup_symbol. If that fails,
- try lookup_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
@@ -1520,15 +1648,14 @@ decode_compound (char **argptr, int funfirstline,
/* Before the call, argptr->"AAA::inA::fun",
p->"", p2->"::fun". After the call: argptr->"fun", p, p2
unchanged. */
- sym_class = lookup_prefix_sym (argptr, p2, file_symtab);
-
- /* If sym_class has been found, and if "AAA::inA" is a class, then
- we're in case 1 above. So we look up "fun" as a method of that
- class. */
- if (sym_class &&
- (t = check_typedef (SYMBOL_TYPE (sym_class)),
- (TYPE_CODE (t) == TYPE_CODE_STRUCT
- || TYPE_CODE (t) == TYPE_CODE_UNION)))
+ 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
@@ -1578,9 +1705,7 @@ decode_compound (char **argptr, int funfirstline,
/* At this point copy->"fun", p->"". */
/* No line number may be specified. */
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
+ *argptr = skip_spaces (p);
/* At this point arptr->"". */
/* Look for copy as a method of sym_class. */
@@ -1590,242 +1715,412 @@ decode_compound (char **argptr, int funfirstline,
here, we return. If not, and we are at the and of the string,
we'll lookup the whole string in the symbol tables. */
- return find_method (funfirstline, canonical, saved_arg, copy, t,
- sym_class, file_symtab);
+ 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. */
+ 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. */
- p = keep_name_info (p, 1);
+ throw_error (NOT_FOUND_ERROR, _("see caller, this text doesn't matter"));
+}
- copy = (char *) alloca (p - saved_arg2 + 1);
- memcpy (copy, saved_arg2, p - saved_arg2);
- /* Note: if is_quoted should be true, we snuff out quote here
- anyway. */
- copy[p - saved_arg2] = '\000';
- /* Set argptr to skip over the name. */
- *argptr = (*p == '\'') ? p + 1 : p;
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* Look up entire name. */
- name = copy;
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
- cleanup = make_cleanup (null_cleanup, NULL);
- canon = cp_canonicalize_string_no_typedefs (copy);
- if (canon != NULL)
- {
- name = canon;
- make_cleanup (xfree, name);
- }
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
- sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0);
- do_cleanups (cleanup);
- if (sym)
- return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
- else
- {
- struct minimal_symbol *msym;
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
- /* Couldn't find any interpretation as classes/namespaces. As a last
- resort, try the minimal symbol tables. */
- msym = lookup_minimal_symbol (copy, NULL, NULL);
- if (msym != NULL)
- return minsym_found (funfirstline, msym);
- }
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
- /* Couldn't find a minimal symbol, either, so give up. */
- cplusplus_error (the_real_saved_arg,
- "Can't find member of namespace, "
- "class, struct, or union named \"%s\"\n",
- copy);
-}
+ if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+ return 1;
+
+ 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;
+
+ slot = htab_find_slot (collector->unique_syms, sym, INSERT);
+ if (!*slot)
+ {
+ *slot = sym;
+ VEC_safe_push (symbolp, collector->symbols, sym);
+ }
-/* Next come some helper functions for decode_compound. */
+ return 1;
+}
/* 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
- lookup_symbol call finds anything (i.e we return NULL). As an
+ this call finds anything (i.e we return NULL). As an
example, say ARGPTR is "AAA::inA::fun" and P is "::inA::fun". */
-static struct symbol *
-lookup_prefix_sym (char **argptr, char *p, struct symtab *file_symtab)
+static VEC (symbolp) *
+lookup_prefix_sym (char **argptr, char *p, VEC (symtab_p) *file_symtabs,
+ char **class_name)
{
char *p1;
char *copy;
- struct symbol *sym;
+ 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 *) alloca (p - *argptr + 1);
+ 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);
- while (*p == ' ' || *p == '\t')
- p++;
+ p = skip_spaces (p);
*argptr = p;
/* At this point p1->"::inA::fun", p->"inA::fun" copy->"AAA",
argptr->"inA::fun". */
- sym = lookup_symbol (copy, get_search_block (file_symtab), STRUCT_DOMAIN, 0);
- if (sym == NULL)
- {
- /* Typedefs are in VAR_DOMAIN so the above symbol lookup will
- fail when the user attempts to lookup a method of a class
- via a typedef'd name (NOT via the class's name, which is already
- handled in symbol_matches_domain). So try the lookup again
- using VAR_DOMAIN (where typedefs live) and double-check that we
- found a struct/class type. */
- struct symbol *s = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
+ collector.symbols = NULL;
+ make_cleanup (VEC_cleanup (symbolp), &collector.symbols);
- if (s != NULL)
- {
- struct type *t = SYMBOL_TYPE (s);
+ collector.unique_syms = htab_create_alloc (1, htab_hash_pointer,
+ htab_eq_pointer, NULL,
+ xcalloc, xfree);
+ cleanup = make_cleanup_htab_delete (collector.unique_syms);
- CHECK_TYPEDEF (t);
- if (TYPE_CODE (t) == TYPE_CODE_STRUCT)
- return s;
+ for (ix = 0; VEC_iterate (symtab_p, file_symtabs, ix, elt); ++ix)
+ {
+ if (elt == NULL)
+ {
+ iterate_over_all_matching_symtabs (copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector,
+ NULL);
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_one_symbol, &collector,
+ NULL);
+ }
+ else
+ {
+ struct block *search_block;
+
+ /* Program spaces that are executing startup should have
+ been filtered out earlier. */
+ 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,
+ collect_one_symbol, &collector);
+ LA_ITERATE_OVER_SYMBOLS (search_block, copy, VAR_DOMAIN,
+ collect_one_symbol, &collector);
}
}
- return sym;
+ do_cleanups (cleanup);
+ discard_cleanups (outer);
+ return collector.symbols;
}
-/* This finds the method COPY in the class whose type is T and whose
- symbol is SYM_CLASS. */
+/* 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 struct symtabs_and_lines
-find_method (int funfirstline, struct linespec_result *canonical,
- char *saved_arg,
- char *copy, struct type *t, struct symbol *sym_class,
- struct symtab *file_symtab)
+static int
+compare_symbols (const void *a, const void *b)
{
- struct symtabs_and_lines values;
- struct symbol *sym = NULL;
- int i1; /* Counter for the symbol array. */
- struct symbol **sym_arr = alloca (total_number_of_methods (t)
- * sizeof (struct symbol *));
+ 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;
- /* Find all methods with a matching name, and put them in
- sym_arr. */
+ if (uia < uib)
+ return -1;
+ if (uia > uib)
+ return 1;
+
+ return 0;
+}
+
+/* Look for all the matching instances of each symbol in NAMES. Only
+ instances from PSPACE are considered; other program spaces are
+ handled by our caller. If PSPACE is NULL, then all program spaces
+ are considered. Results are stored into INFO. */
+
+static void
+add_all_symbol_names_from_pspace (struct collect_info *info,
+ struct program_space *pspace,
+ VEC (const_char_ptr) *names)
+{
+ int ix;
+ const char *iter;
+
+ for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix)
+ add_matching_symbols_to_info (iter, info, pspace);
+}
- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
- file_symtab);
+static void
+find_superclass_methods (VEC (typep) *superclasses,
+ const char *name,
+ VEC (const_char_ptr) **result_names)
+{
+ int old_len = VEC_length (const_char_ptr, *result_names);
+ VEC (typep) *iter_classes;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
- /* If we were given a specific overload instance in COPY, defer the field
- acceptance till the strcmp_iw verification below, even if we found just
- a single field with that name. */
- if (i1 == 1 && strchr (copy, '(') == NULL)
+ iter_classes = superclasses;
+ while (1)
{
- /* There is exactly one field with that name. */
- sym = sym_arr[0];
+ VEC (typep) *new_supers = NULL;
+ int ix;
+ struct type *t;
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- values.sals[0] = find_function_start_sal (sym,
- funfirstline);
- }
- else
+ make_cleanup (VEC_cleanup (typep), &new_supers);
+ for (ix = 0; VEC_iterate (typep, iter_classes, ix, t); ++ix)
+ find_methods (t, name, result_names, &new_supers);
+
+ if (VEC_length (const_char_ptr, *result_names) != old_len
+ || VEC_empty (typep, new_supers))
+ break;
+
+ iter_classes = new_supers;
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* This finds the method COPY in the class whose type is given by one
+ of the symbols in SYM_CLASSES. */
+
+static struct symtabs_and_lines
+find_method (struct linespec_state *self, char *saved_arg,
+ char *copy, const char *class_name, VEC (symbolp) *sym_classes)
+{
+ char *canon;
+ struct symbol *sym;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ int ix;
+ int last_result_len;
+ 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. */
+ qsort (VEC_address (symbolp, sym_classes),
+ VEC_length (symbolp, sym_classes),
+ sizeof (symbolp),
+ compare_symbols);
+
+ info.state = self;
+ info.result.sals = NULL;
+ info.result.nelts = 0;
+ info.objfile = NULL;
+
+ /* Iterate over all the types, looking for the names of existing
+ methods matching COPY. 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
+ need to collect the names because later we find all symbols with
+ those names. This loop is written in a somewhat funny way
+ because we collect data across the program space before deciding
+ what to do. */
+ superclass_vec = NULL;
+ make_cleanup (VEC_cleanup (typep), &superclass_vec);
+ result_names = NULL;
+ make_cleanup (VEC_cleanup (const_char_ptr), &result_names);
+ last_result_len = 0;
+ for (ix = 0; VEC_iterate (symbolp, sym_classes, ix, sym); ++ix)
+ {
+ struct type *t;
+ struct program_space *pspace;
+
+ /* Program spaces that are executing startup should have
+ been filtered out earlier. */
+ gdb_assert (!SYMTAB_PSPACE (SYMBOL_SYMTAB (sym))->executing_startup);
+ 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);
+
+ /* Handle all items from a single program space at once; and be
+ sure not to miss the last batch. */
+ if (ix == VEC_length (symbolp, sym_classes) - 1
+ || (pspace
+ != SYMTAB_PSPACE (SYMBOL_SYMTAB (VEC_index (symbolp, sym_classes,
+ ix + 1)))))
{
- values.sals = NULL;
- values.nelts = 0;
+ /* 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);
+
+ /* We have a list of candidate symbol names, so now we
+ iterate over the symbol tables looking for all
+ matches in this pspace. */
+ add_all_symbol_names_from_pspace (&info, pspace, result_names);
+
+ VEC_truncate (typep, superclass_vec, 0);
+ last_result_len = VEC_length (const_char_ptr, result_names);
}
- return values;
}
- if (i1 > 0)
+
+ if (info.result.nelts > 0)
{
- /* If we were given a specific overload instance, use that
- (or error if no matches were found). Otherwise ask the user
- which one to use. */
- if (strchr (copy, '('))
+ if (self->canonical)
{
- int i;
- char *name;
- char *canon;
- struct cleanup *cleanup;
-
- /* Construct the proper search name based on SYM_CLASS and COPY.
- SAVED_ARG may contain a valid name, but that name might not be
- what is actually stored in the symbol table. For example,
- if SAVED_ARG (and SYM_CLASS) were found via an import
- ("using namespace" in C++), then the physname of
- SYM_CLASS ("A::myclass") may not be the same as SAVED_ARG
- ("myclass"). */
- name = xmalloc (strlen (SYMBOL_NATURAL_NAME (sym_class))
- + 2 /* "::" */ + strlen (copy) + 1);
- strcpy (name, SYMBOL_NATURAL_NAME (sym_class));
- strcat (name, "::");
- strcat (name, copy);
- canon = cp_canonicalize_string_no_typedefs (name);
- if (canon != NULL)
- {
- xfree (name);
- name = canon;
- }
- cleanup = make_cleanup (xfree, name);
-
- for (i = 0; i < i1; ++i)
- {
- if (strcmp_iw (name, SYMBOL_LINKAGE_NAME (sym_arr[i])) == 0)
- {
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- values.sals[0] = find_function_start_sal (sym_arr[i],
- funfirstline);
- do_cleanups (cleanup);
- return values;
- }
- }
-
- cplusplus_error (saved_arg, _("the class `%s' does not have "
- "any method instance named %s"),
- SYMBOL_PRINT_NAME (sym_class), copy);
+ 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);
}
- return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ do_cleanups (cleanup);
+
+ return info.result;
}
+
+ 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);
+}
+
+
+
+/* This object is used when collecting all matching symtabs. */
+
+struct symtab_collector
+{
+ /* The result vector of symtabs. */
+ VEC (symtab_p) *symtabs;
+
+ /* This is used to ensure the symtabs are unique. */
+ htab_t symtab_table;
+};
+
+/* Callback for iterate_over_symtabs. */
+
+static int
+add_symtabs_to_list (struct symtab *symtab, void *d)
+{
+ struct symtab_collector *data = d;
+ void **slot;
+
+ slot = htab_find_slot (data->symtab_table, symtab, INSERT);
+ if (!*slot)
{
- if (copy[0] == '~')
- cplusplus_error (saved_arg,
- "the class `%s' does not have destructor defined\n",
- SYMBOL_PRINT_NAME (sym_class));
- else
- cplusplus_error (saved_arg,
- "the class %s does not have any method named %s\n",
- SYMBOL_PRINT_NAME (sym_class), copy);
+ *slot = symtab;
+ VEC_safe_push (symtab_p, data->symtabs, symtab);
}
+
+ return 0;
}
-
+/* Given a file name, return a VEC of all matching symtabs. */
+
+static VEC (symtab_p) *
+collect_symtabs_from_filename (const char *file)
+{
+ struct symtab_collector collector;
+ struct cleanup *cleanups;
+ struct program_space *pspace;
+
+ collector.symtabs = NULL;
+ collector.symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer,
+ NULL);
+ cleanups = make_cleanup_htab_delete (collector.symtab_table);
+
+ /* Find that file's data. */
+ ALL_PSPACES (pspace)
+ {
+ if (pspace->executing_startup)
+ continue;
+
+ set_current_program_space (pspace);
+ iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+ }
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+ do_cleanups (cleanups);
+ 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. */
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+static VEC (symtab_p) *
+symtabs_from_filename (char **argptr, char *p, int is_quote_enclosed,
+ char **user_filename)
{
char *p1;
char *copy;
- struct symtab *file_symtab;
+ struct cleanup *outer;
+ VEC (symtab_p) *result;
p1 = p;
while (p != *argptr && p[-1] == ' ')
--p;
if ((*p == '"') && is_quote_enclosed)
--p;
- copy = (char *) alloca (p - *argptr + 1);
+ 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] == '"')
@@ -1834,9 +2129,9 @@ symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
else
copy[p - *argptr] = 0;
- /* Find that file's data. */
- file_symtab = lookup_symtab (copy);
- if (file_symtab == 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,
@@ -1847,31 +2142,47 @@ symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
/* Discard the file name from the arg. */
if (*p1 == '\0')
- return file_symtab;
- p = p1 + 1;
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
+ *argptr = p1;
+ else
+ *argptr = skip_spaces (p1 + 1);
- return file_symtab;
+ 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 struct symbol *
-find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
+static VEC (symbolp) *
+find_function_symbols (char **argptr, char *p, int is_quote_enclosed,
+ char **user_function)
{
char *p1;
char *copy;
- struct symbol *function_symbol;
+ VEC (symbolp) *result = NULL;
p1 = p;
while (p != *argptr && p[-1] == ' ')
--p;
if ((*p == '"') && is_quote_enclosed)
--p;
- copy = (char *) alloca (p - *argptr + 1);
+ 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] == '"')
@@ -1880,34 +2191,106 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
else
copy[p - *argptr] = 0;
- function_symbol = lookup_symbol (copy, get_selected_block (0),
- VAR_DOMAIN, 0);
- if (!function_symbol || SYMBOL_CLASS (function_symbol) != LOC_BLOCK)
- return NULL;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols, &result, NULL);
- /* Discard the file name from the arg. */
- p = p1 + 1;
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ 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 (char **argptr, struct symtab *default_symtab,
- int default_line, struct linespec_result *canonical,
- struct symtab *file_symtab, char *q)
-
+decode_all_digits (struct linespec_state *self,
+ char **argptr,
+ char *q)
{
struct symtabs_and_lines values;
struct symtab_and_line val;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1915,12 +2298,9 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
}
sign = none;
- /* We might need a canonical line spec if no file was specified. */
- int need_canonical = (file_symtab == NULL) ? 1 : 0;
-
init_sal (&val);
-
- val.pspace = current_program_space;
+ 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
@@ -1928,11 +2308,19 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
set_default_source_symtab_and_line uses
select_source_symtab that calls us with such an argument. */
- if (file_symtab == 0 && default_symtab == 0)
+ 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 (&default_symtab, &default_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 == '+')
@@ -1945,14 +2333,14 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
case plus:
if (q == *argptr)
val.line = 5;
- if (file_symtab == 0)
- val.line = default_line + val.line;
+ if (use_default)
+ val.line = self->default_line + val.line;
break;
case minus:
if (q == *argptr)
val.line = 15;
- if (file_symtab == 0)
- val.line = default_line - val.line;
+ if (use_default)
+ val.line = self->default_line - val.line;
else
val.line = 1;
break;
@@ -1960,28 +2348,110 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
break; /* No need to adjust val.line. */
}
- while (*q == ' ' || *q == '\t')
- q++;
- *argptr = q;
- if (file_symtab == 0)
- file_symtab = default_symtab;
-
- /* It is possible that this source file has more than one symtab,
- and that the new line number specification has moved us from the
- default (in file_symtab) to a new one. */
- val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
- if (val.symtab == 0)
- val.symtab = file_symtab;
-
- val.pspace = SYMTAB_PSPACE (val.symtab);
- val.pc = 0;
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = val;
- values.nelts = 1;
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
- values.sals[0].explicit_line = 1;
+ *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);
+ }
+
+ if (self->canonical)
+ {
+ 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);
+ }
+
return values;
}
@@ -1990,17 +2460,17 @@ decode_all_digits (char **argptr, struct symtab *default_symtab,
/* Decode a linespec starting with a dollar sign. */
static struct symtabs_and_lines
-decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
- struct linespec_result *canonical, struct symtab *file_symtab)
+decode_dollar (struct linespec_state *self, char *copy)
{
LONGEST valx;
int index = 0;
- int need_canonical = 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;
p = (copy[1] == '$') ? copy + 2 : copy + 1;
while (*p >= '0' && *p <= '9')
@@ -2022,19 +2492,18 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
/* Not all digits -- may be user variable/function or a
convenience variable. */
- /* Look up entire name as a symbol first. */
- sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
- file_symtab = (struct symtab *) NULL;
- need_canonical = 1;
- /* Symbol was found --> jump to normal symbol processing. */
- if (sym)
- return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
+ volatile struct gdb_exception exc;
+
+ TRY_CATCH (exc, RETURN_MASK_ERROR)
+ {
+ values = decode_variable (self, copy);
+ }
+
+ if (exc.reason == 0)
+ return values;
- /* If symbol was not found, look in minimal symbol tables. */
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
- /* Min symbol was found --> jump to minsym processing. */
- if (msymbol)
- return minsym_found (funfirstline, msymbol);
+ if (exc.error != NOT_FOUND_ERROR)
+ throw_exception (exc);
/* Not a user variable or function -- must be convenience variable. */
if (!get_internalvar_integer (lookup_internalvar (copy + 1), &valx))
@@ -2044,18 +2513,37 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
init_sal (&val);
- /* Either history value or convenience value from above, in valx. */
- val.symtab = file_symtab ? file_symtab : default_symtab;
- val.line = valx;
- val.pc = 0;
- val.pspace = current_program_space;
+ values.sals = NULL;
+ values.nelts = 0;
- values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
- values.sals[0] = val;
- values.nelts = 1;
+ for (ix = 0; VEC_iterate (symtab_p, self->file_symtabs, ix, elt); ++ix)
+ {
+ if (elt == NULL)
+ {
+ elt = self->default_symtab;
+ set_current_program_space (self->program_space);
+ }
+ 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;
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ 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);
+ }
return values;
}
@@ -2064,7 +2552,7 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
/* A helper for decode_line_1 that tries to find a label. The label
is searched for in the current block.
- FUNCTION_SYMBOL is the enclosing function; or NULL if none
+ 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.
@@ -2073,78 +2561,299 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
This function returns 1 if a label was found, 0 otherwise. */
static int
-decode_label (struct symbol *function_symbol, char *copy,
- struct linespec_result *canonical,
+decode_label (struct linespec_state *self,
+ VEC (symbolp) *function_symbols, char *copy,
struct symtabs_and_lines *result)
{
- struct symbol *sym;
- struct block *block;
+ struct symbol *fn_sym;
+ int ix;
- if (function_symbol)
- block = SYMBOL_BLOCK_VALUE (function_symbol);
- else
+ if (function_symbols == NULL)
{
- block = get_selected_block (0);
+ 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);
+
for (;
block && !BLOCK_FUNCTION (block);
block = BLOCK_SUPERBLOCK (block))
;
if (!block)
return 0;
- function_symbol = BLOCK_FUNCTION (block);
+ fn_sym = BLOCK_FUNCTION (block);
+
+ sym = lookup_symbol (copy, 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)
+ {
+ self->canonical->special_display = 1;
+ self->canonical->addr_string
+ = xstrprintf ("%s:%s", SYMBOL_NATURAL_NAME (fn_sym),
+ copy);
+ }
+
+ *result = values;
+
+ return 1;
}
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+ result->sals = NULL;
+ result->nelts = 0;
+
+ for (ix = 0; VEC_iterate (symbolp, function_symbols, ix, fn_sym); ++ix)
+ {
+ struct block *block;
+ struct symbol *sym;
+
+ set_current_program_space (SYMTAB_PSPACE (SYMBOL_SYMTAB (fn_sym)));
+ block = SYMBOL_BLOCK_VALUE (fn_sym);
+ sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+ if (sym != NULL)
+ {
+ 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);
+ }
+ }
+
+ if (self->canonical && result->nelts > 0)
+ {
+ self->canonical->pre_expanded = 1;
+ self->canonical->special_display = 1;
- return sym != NULL;
+ gdb_assert (self->user_function);
+ self->canonical->addr_string
+ = xstrprintf ("%s:%s", self->user_function, copy);
+ }
+
+ return result->nelts > 0;
+}
+
+/* A callback used to possibly add a symbol to the results. */
+
+static int
+collect_symbols (struct symbol *sym, void *data)
+{
+ struct collect_info *info = data;
+ struct symtab_and_line sal;
+
+ if ((SYMBOL_CLASS (sym) == LOC_STATIC
+ && !info->state->funfirstline
+ && !maybe_add_address (info->state->addr_set,
+ SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
+ SYMBOL_VALUE_ADDRESS (sym)))
+ || (SYMBOL_CLASS (sym) == LOC_BLOCK
+ && !maybe_add_address (info->state->addr_set,
+ SYMTAB_PSPACE (SYMBOL_SYMTAB (sym)),
+ BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))))
+ {
+ /* Nothing. */
+ }
+ else if (symbol_to_sal (&sal, info->state->funfirstline, sym))
+ add_sal_to_sals (info->state, &info->result, &sal,
+ SYMBOL_NATURAL_NAME (sym));
+
+ return 1;
+}
+
+/* We've found a minimal symbol MSYMBOL to associate with our
+ linespec; add it to the result symtabs_and_lines. */
+
+static void
+minsym_found (struct linespec_state *self, struct objfile *objfile,
+ struct minimal_symbol *msymbol,
+ struct symtabs_and_lines *result)
+{
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ CORE_ADDR pc;
+ struct symtab_and_line sal;
+
+ sal = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
+ (struct obj_section *) 0, 0);
+ sal.section = SYMBOL_OBJ_SECTION (msymbol);
+
+ /* The minimal symbol might point to a function descriptor;
+ resolve it to the actual code address instead. */
+ pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, &current_target);
+ if (pc != sal.pc)
+ sal = find_pc_sect_line (pc, NULL, 0);
+
+ if (self->funfirstline)
+ skip_prologue_sal (&sal);
+
+ add_sal_to_sals (self, result, &sal, SYMBOL_NATURAL_NAME (msymbol));
+}
+
+/* Callback for iterate_over_minimal_symbols that may add the symbol
+ to the result. */
+
+static void
+check_minsym (struct minimal_symbol *minsym, void *d)
+{
+ struct collect_info *info = d;
+
+ if (MSYMBOL_TYPE (minsym) == mst_unknown
+ || MSYMBOL_TYPE (minsym) == mst_slot_got_plt
+ || MSYMBOL_TYPE (minsym) == mst_solib_trampoline)
+ {
+ /* Reject some odd ones. */
+ }
+ else if (info->state->funfirstline
+ && MSYMBOL_TYPE (minsym) != mst_text
+ && MSYMBOL_TYPE (minsym) != mst_text_gnu_ifunc
+ && MSYMBOL_TYPE (minsym) != mst_file_text)
+ {
+ /* When FUNFIRSTLINE, only allow text symbols. */
+ }
+ else if (maybe_add_address (info->state->addr_set, info->objfile->pspace,
+ SYMBOL_VALUE_ADDRESS (minsym)))
+ minsym_found (info->state, info->objfile, minsym, &info->result);
+}
+
+/* Search minimal symbols in all objfiles for NAME. If SEARCH_PSPACE
+ is not NULL, the search is restricted to just that program
+ space. */
+
+static void
+search_minsyms_for_name (struct collect_info *info, const char *name,
+ struct program_space *search_pspace)
+{
+ struct objfile *objfile;
+ struct program_space *pspace;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
+ if (pspace->executing_startup)
+ continue;
+
+ set_current_program_space (pspace);
+
+ ALL_OBJFILES (objfile)
+ {
+ info->objfile = objfile;
+ iterate_over_minimal_symbols (objfile, name, check_minsym, info);
+ }
+ }
+}
+
+/* A helper function to add all symbols matching NAME to INFO. If
+ PSPACE is not NULL, the search is restricted to just that program
+ space. */
+
+static void
+add_matching_symbols_to_info (const char *name,
+ struct collect_info *info,
+ struct program_space *pspace)
+{
+ int ix;
+ struct symtab *elt;
+
+ for (ix = 0; VEC_iterate (symtab_p, info->state->file_symtabs, ix, elt); ++ix)
+ {
+ struct symbol *sym;
+
+ if (elt == NULL)
+ {
+ iterate_over_all_matching_symtabs (name, VAR_DOMAIN,
+ collect_symbols, info,
+ pspace);
+ search_minsyms_for_name (info, name, pspace);
+ }
+ else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt))
+ {
+ /* Program spaces that are executing startup should have
+ been filtered out earlier. */
+ gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
+ set_current_program_space (SYMTAB_PSPACE (elt));
+ LA_ITERATE_OVER_SYMBOLS (get_search_block (elt), name,
+ VAR_DOMAIN, collect_symbols,
+ info);
+ }
+ }
}
/* 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 (char *copy, int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab)
+decode_variable (struct linespec_state *self, char *copy)
{
- char *name, *canon;
- struct symbol *sym;
+ struct collect_info info;
+ const char *lookup_name;
+ char *canon;
struct cleanup *cleanup;
- struct minimal_symbol *msymbol;
- name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
- canon = cp_canonicalize_string_no_typedefs (copy);
- if (canon != NULL)
+ info.state = self;
+ info.result.sals = NULL;
+ info.result.nelts = 0;
+ info.objfile = NULL;
+
+ cleanup = demangle_for_lookup (copy, current_language->la_language,
+ &lookup_name);
+ if (current_language->la_language == language_ada)
{
- name = canon;
- make_cleanup (xfree, name);
+ /* 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);
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
-
- if (sym != NULL)
+ canon = cp_canonicalize_string_no_typedefs (lookup_name);
+ if (canon != NULL)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (msymbol != NULL)
- return minsym_found (funfirstline, msymbol);
+ 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."));
- throw_error (NOT_FOUND_ERROR, _("Function \"%s\" not defined."), copy);
+ 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);
}
@@ -2153,130 +2862,82 @@ decode_variable (char *copy, int funfirstline,
/* Now come some functions that are called from multiple places within
decode_line_1. */
-/* We've found a symbol SYM to associate with our linespec; build a
- corresponding struct symtabs_and_lines. */
-
-static struct symtabs_and_lines
-symbol_found (int funfirstline, struct linespec_result *canonical, char *copy,
- struct symbol *sym, struct symtab *file_symtab,
- struct symbol *function_symbol)
+static int
+symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym)
{
- struct symtabs_and_lines values;
-
if (SYMBOL_CLASS (sym) == LOC_BLOCK)
{
- /* Arg is the name of a function. */
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = find_function_start_sal (sym, funfirstline);
- values.nelts = 1;
-
- /* Don't use the SYMBOL_LINE; if used at all it points to
- the line containing the parameters or thereabouts, not
- the first line of code. */
-
- /* We might need a canonical line spec if it is a static
- function. */
- if (file_symtab == 0)
- {
- struct blockvector *bv = BLOCKVECTOR (SYMBOL_SYMTAB (sym));
- struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
-
- if (lookup_block_symbol (b, copy, VAR_DOMAIN) != NULL)
- build_canonical_line_spec (values.sals, copy, canonical);
- }
- return values;
+ *result = find_function_start_sal (sym, funfirstline);
+ return 1;
}
else
{
if (SYMBOL_CLASS (sym) == LOC_LABEL && SYMBOL_VALUE_ADDRESS (sym) != 0)
{
- /* We know its line number. */
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- init_sal (&values.sals[0]);
- values.sals[0].symtab = SYMBOL_SYMTAB (sym);
- values.sals[0].line = SYMBOL_LINE (sym);
- values.sals[0].pc = SYMBOL_VALUE_ADDRESS (sym);
- values.sals[0].pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
- values.sals[0].explicit_pc = 1;
-
- if (canonical)
- {
- canonical->special_display = 1;
- canonical->canonical = xmalloc (sizeof (char *));
- canonical->canonical[0]
- = xstrprintf ("%s:%s",
- SYMBOL_NATURAL_NAME (function_symbol),
- SYMBOL_NATURAL_NAME (sym));
- }
-
- return values;
+ init_sal (result);
+ result->symtab = SYMBOL_SYMTAB (sym);
+ result->line = SYMBOL_LINE (sym);
+ result->pc = SYMBOL_VALUE_ADDRESS (sym);
+ result->pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+ result->explicit_pc = 1;
+ return 1;
}
else if (funfirstline)
{
- /* NOT_FOUND_ERROR is not correct but it ensures COPY will be
- searched also as a minimal symbol. */
-
- throw_error (NOT_FOUND_ERROR, _("\"%s\" is not a function"), copy);
+ /* Nothing. */
}
else if (SYMBOL_LINE (sym) != 0)
{
/* We know its line number. */
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- memset (&values.sals[0], 0, sizeof (values.sals[0]));
- values.sals[0].symtab = SYMBOL_SYMTAB (sym);
- values.sals[0].line = SYMBOL_LINE (sym);
- values.sals[0].pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
- return values;
+ init_sal (result);
+ result->symtab = SYMBOL_SYMTAB (sym);
+ result->line = SYMBOL_LINE (sym);
+ result->pspace = SYMTAB_PSPACE (SYMBOL_SYMTAB (sym));
+ return 1;
}
- else
- /* This can happen if it is compiled with a compiler which doesn't
- put out line numbers for variables. */
- /* FIXME: Shouldn't we just set .line and .symtab to zero
- and return? For example, "info line foo" could print
- the address. */
- error (_("Line number not known for symbol \"%s\""), copy);
}
+
+ return 0;
}
-/* We've found a minimal symbol MSYMBOL to associate with our
- linespec; build a corresponding struct symtabs_and_lines. */
+/* See the comment in linespec.h. */
-static struct symtabs_and_lines
-minsym_found (int funfirstline, struct minimal_symbol *msymbol)
+void
+init_linespec_result (struct linespec_result *lr)
{
- struct objfile *objfile = msymbol_objfile (msymbol);
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- struct symtabs_and_lines values;
- CORE_ADDR pc;
+ memset (lr, 0, sizeof (*lr));
+}
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
- (struct obj_section *) 0, 0);
- values.sals[0].section = SYMBOL_OBJ_SECTION (msymbol);
+/* See the comment in linespec.h. */
- /* The minimal symbol might point to a function descriptor;
- resolve it to the actual code address instead. */
- pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
- values.sals[0].pc,
- &current_target);
- if (pc != values.sals[0].pc)
- values.sals[0] = find_pc_sect_line (pc, NULL, 0);
+void
+destroy_linespec_result (struct linespec_result *ls)
+{
+ int i;
+ struct linespec_sals *lsal;
+
+ xfree (ls->addr_string);
+ for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
+ {
+ xfree (lsal->canonical);
+ xfree (lsal->sals.sals);
+ }
+ VEC_free (linespec_sals, ls->sals);
+}
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+/* Cleanup function for a linespec_result. */
- values.nelts = 1;
- return values;
+static void
+cleanup_linespec_result (void *a)
+{
+ destroy_linespec_result (a);
}
-void
-init_linespec_result (struct linespec_result *lr)
+/* See the comment in linespec.h. */
+
+struct cleanup *
+make_cleanup_destroy_linespec_result (struct linespec_result *ls)
{
- memset (lr, 0, sizeof (*lr));
+ return make_cleanup (cleanup_linespec_result, ls);
}