* RFA: implement ambiguous linespec proposal
@ 2011-10-28 17:34 Tom Tromey
2011-10-28 20:52 ` Matt Rice
2011-10-28 22:41 ` Jan Kratochvil
0 siblings, 2 replies; 42+ messages in thread
From: Tom Tromey @ 2011-10-28 17:34 UTC (permalink / raw)
To: gdb-patches
I'd appreciate comments on this patch.
This implements the ambiguous linespec proposal agreed on earlier this
year: http://sourceware.org/ml/gdb-patches/2011-07/msg00036.html
This also fixes a number of bugs.
The patch relies on the two patches I posted yesterday.
I didn't see a better way to split this patch up, so I will try to
describe the relevant bits.
Most of the work was changing linespec.c to loop over program spaces and
symbol tables, rather than being satisfied by a single hit in the
current program space. This required a change to a
quick_symbol_functions method and various new functions in the symtab
and minsyms code.
Because I was making so many changes in linespec, I "objectified" it --
I introduced a state struct which is passed around inside the module. I
think this is an improvement; before I did this the various helper
functions were getting an unwieldy number of arguments.
There are two new entry points to linespec.
decode_line_full is used by the breakpoint code. It returns extended
information about the linespec, for example a canonical form for each
SAL.
decode_line_list is only used by 'list' and 'edit' and it has a special
tweak for FILE:LINE linespecs only. This is sort of ugly but I didn't
see a better way.
I think the new linespec is generally cleaner and more correct now.
multiple-symbols changed slightly, per the spec. Now the 'all' choice
acts just like multiple-symbols=all. Filtering in the select case is
done by simply comparing the canonical form returned by decode_line_full
for the selected SAL against the canonical forms returned by subsequent
calls to decode_line_full.
For breakpoints, I pushed the file:line location info into the
bp_location. This required changes here and there, including some
output changes. I don't consider these very serious.
I removed expand_line_sal_maybe, as this is now done entirely in
linespec.
I made the discussed change to ranged breakpoints: they disable if
re-setting discovers too many locations.
I went through all the other users of decode_line_1 (and its wrappers
decode_line_spec_1 and decode_line_spec) to see if they needed changes.
In some cases (list, edit) this meant filtering and a special API. In
others I chose to skip SALs coming from other program spaces.
While working on this patch I found a number of other things that could
be done. I chose the draw the line where I did because I think this
patch is reasonably useful and complete, while already being a bit too
large.
So, future stuff. I may do some of these, not sure yet.
* Rebase sdt.h probe patches on top of this.
I definitely plan to do this one.
* Add new linespecs, like OBJFILE:FILE:FUNCTION and FILE:FUNCTION:LINE.
This will be easier with some changes Keith is making.
* Let "break a/file.c:5" match "x/a/file.c"
* Add the discussed "final" flag to breakpoints.
(I have been considering perhaps doing this via I/T sets though.)
* Make breakpoint re-setting more fine-grained. We don't really need to
search all the symbols everywhere -- just the new or changed objfile.
* Add a split form for linespecs, like break -o objfile -s source -f function.
Also do this for MI.
I built and regression tested this on x86-64 F15.
It comes with some new tests, though not very many.
I did find that our test suite covers linespec reasonably well -- it
found a number of regressions in my initial patches, and also I used
gcov to examine the coverage of linespec.c; I consider it pretty good.
Tom
2011-10-28 Tom Tromey <tromey@redhat.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:
* 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.
* 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.
* 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.
(compare_core_addrs, find_pcs_for_symtab_line): New functions.
(find_line_common): Add 'start' argument.
(decode_line_spec): Update.
* 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.
* source.c (line_info): Set pspace on sal. Check program space in
the loop.
* 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 (struct linespec_sals): New type.
(struct linespec_result) <canonical>: Remove.
<pre_expanded, addr_string, sals>: New fields.
(destroy_linespec_result, make_cleanup_destroy_linespec_result)
(decode_line_list, 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, decode_line_list): 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. Fall back on
decode_variable.
(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.
* 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. 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.
(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.
* block.h (block_containing_function): Declare.
* block.c (block_containing_function): New function.
2011-10-28 Tom Tromey <tromey@redhat.com>
* 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/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.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.
From e1c0d9d7e67ef398e55e09f3d51afa9126dbc840 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 27 Oct 2011 09:26:30 -0600
Subject: [PATCH 3/3] the rewrite
---
gdb/ChangeLog | 148 ++
gdb/block.c | 14 +
gdb/block.h | 2 +
gdb/breakpoint.c | 538 +++---
gdb/breakpoint.h | 21 +-
gdb/cli/cli-cmds.c | 103 +-
gdb/defs.h | 1 +
gdb/dwarf2loc.c | 3 -
gdb/dwarf2read.c | 60 +-
gdb/linespec.c | 2452 +++++++++++++++---------
gdb/linespec.h | 100 +-
gdb/minsyms.c | 40 +
gdb/objc-lang.c | 288 +--
gdb/objc-lang.h | 12 +-
gdb/psymtab.c | 80 +-
gdb/python/py-type.c | 14 +-
gdb/python/python.c | 2 +-
gdb/solib-target.c | 2 -
gdb/source.c | 8 +-
gdb/stack.c | 16 +-
gdb/symfile.h | 34 +-
gdb/symtab.c | 372 +++-
gdb/symtab.h | 34 +
gdb/testsuite/ChangeLog | 31 +
gdb/testsuite/Makefile.in | 2 +-
gdb/testsuite/configure | 3 +-
gdb/testsuite/configure.ac | 2 +-
gdb/testsuite/gdb.base/break.exp | 3 +-
gdb/testsuite/gdb.base/list.exp | 2 +-
gdb/testsuite/gdb.base/sepdebug.exp | 3 +-
gdb/testsuite/gdb.base/solib-symbol.exp | 14 +-
gdb/testsuite/gdb.cp/mb-ctor.exp | 4 +-
gdb/testsuite/gdb.cp/mb-inline.exp | 4 +-
gdb/testsuite/gdb.cp/mb-templates.exp | 6 +-
gdb/testsuite/gdb.cp/method2.exp | 2 +-
gdb/testsuite/gdb.cp/ovldbreak.exp | 79 +-
gdb/testsuite/gdb.cp/re-set-overloaded.exp | 1 -
gdb/testsuite/gdb.cp/templates.exp | 4 +-
gdb/testsuite/gdb.linespec/Makefile.in | 14 +
gdb/testsuite/gdb.linespec/base/one/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/base/two/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/linespec.exp | 106 +
gdb/testsuite/gdb.linespec/lspec.cc | 13 +
gdb/testsuite/gdb.linespec/lspec.h | 9 +
gdb/testsuite/gdb.objc/objcdecode.exp | 2 +-
gdb/testsuite/gdb.trace/tracecmd.exp | 2 +-
gdb/tracepoint.c | 2 +-
gdb/tui/tui-winsource.c | 47 +-
gdb/utils.c | 11 +
49 files changed, 2995 insertions(+), 1753 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/Makefile.in
create mode 100644 gdb/testsuite/gdb.linespec/base/one/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/base/two/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/linespec.exp
create mode 100644 gdb/testsuite/gdb.linespec/lspec.cc
create mode 100644 gdb/testsuite/gdb.linespec/lspec.h
diff --git a/gdb/block.c b/gdb/block.c
index c165bc2..1fa3688 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -82,6 +82,20 @@ block_linkage_function (const struct block *bl)
return BLOCK_FUNCTION (bl);
}
+/* Return the symbol for the function which contains a specified
+ block, described by a struct block BL. The return value will be
+ the closest enclosing function, which might be an inline
+ function. */
+
+struct symbol *
+block_containing_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
/* Return one if BL represents an inlined function. */
int
diff --git a/gdb/block.h b/gdb/block.h
index 1742f24..63b18a6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -131,6 +131,8 @@ struct blockvector
extern struct symbol *block_linkage_function (const struct block *);
+extern struct symbol *block_containing_function (const struct block *);
+
extern int block_inlined_p (const struct block *block);
extern int contained_in (const struct block *, const struct block *);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1c6a43b..7b5c188 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4559,7 +4559,7 @@ print_breakpoint_location (struct breakpoint *b,
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (b->source_file && loc)
+ else if (loc && loc->source_file)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
@@ -4572,7 +4572,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_field_string (uiout, "file", loc->source_file);
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
@@ -4584,7 +4584,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_field_string (uiout, "fullname", fullname);
}
- ui_out_field_int (uiout, "line", b->line_number);
+ ui_out_field_int (uiout, "line", loc->line_number);
}
else if (loc)
{
@@ -5825,12 +5825,10 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sal.symtab->filename);
+ if (sal.symtab != NULL)
+ b->loc->source_file = xstrdup (sal.symtab->filename);
b->loc->section = sal.section;
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
set_breakpoint_location_function (b->loc,
sal.explicit_pc || sal.explicit_line);
@@ -7065,12 +7063,10 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
- if (orig->source_file == NULL)
- copy->source_file = NULL;
- else
- copy->source_file = xstrdup (orig->source_file);
+ if (orig->loc->source_file != NULL)
+ copy->loc->source_file = xstrdup (orig->loc->source_file);
- copy->line_number = orig->line_number;
+ copy->loc->line_number = orig->loc->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
@@ -7142,6 +7138,10 @@ add_location_to_breakpoint (struct breakpoint *b,
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
+ if (sal->symtab != NULL)
+ loc->source_file = xstrdup (sal->symtab->filename);
+ loc->line_number = sal->line;
+
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
return loc;
@@ -7198,7 +7198,7 @@ bp_loc_is_permanent (struct bp_location *loc)
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7312,12 +7312,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
me. */
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->filter = filter;
}
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7340,7 +7341,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- cond_string,
+ filter, cond_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
@@ -7350,138 +7351,6 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
install_breakpoint (internal, b);
}
-/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
- elements to fill the void space. */
-static void
-remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
-{
- int i = index_to_remove+1;
- int last_index = sal->nelts-1;
-
- for (;i <= last_index; ++i)
- sal->sals[i-1] = sal->sals[i];
-
- --(sal->nelts);
-}
-
-/* If appropriate, obtains all sals that correspond to the same file
- and line as SAL, in all program spaces. Users debugging with IDEs,
- will want to set a breakpoint at foo.c:line, and not really care
- about program spaces. This is done only if SAL does not have
- explicit PC and has line and file information. If we got just a
- single expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out all sals for
- which the name of enclosing function is different from SAL. This
- makes sure that if we have breakpoint originally set in template
- instantiation, say foo<int>(), we won't expand SAL to locations at
- the same line in all existing instantiations of 'foo'. */
-
-static struct symtabs_and_lines
-expand_line_sal_maybe (struct symtab_and_line sal)
-{
- struct symtabs_and_lines expanded;
- CORE_ADDR original_pc = sal.pc;
- char *original_function = NULL;
- int found;
- int i;
- struct cleanup *old_chain;
-
- /* If we have explicit pc, don't expand.
- If we have no line number, we can't expand. */
- if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
- {
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sal;
- return expanded;
- }
-
- sal.pc = 0;
-
- old_chain = save_current_space_and_thread ();
-
- switch_to_program_space_and_thread (sal.pspace);
-
- find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
- /* Note that expand_line_sal visits *all* program spaces. */
- expanded = expand_line_sal (sal);
-
- if (expanded.nelts == 1)
- {
- /* We had one sal, we got one sal. Return that sal, adjusting it
- past the function prologue if necessary. */
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- skip_prologue_sal (&expanded.sals[0]);
- do_cleanups (old_chain);
- return expanded;
- }
-
- if (!sal.explicit_line)
- {
- CORE_ADDR func_addr, func_end;
- for (i = 0; i < expanded.nelts; ++i)
- {
- CORE_ADDR pc = expanded.sals[i].pc;
- char *this_function;
-
- /* We need to switch threads as well since we're about to
- read memory. */
- switch_to_program_space_and_thread (expanded.sals[i].pspace);
-
- if (find_pc_partial_function (pc, &this_function,
- &func_addr, &func_end))
- {
- if (this_function
- && strcmp (this_function, original_function) != 0)
- {
- remove_sal (&expanded, i);
- --i;
- }
- }
- }
- }
-
- /* Skip the function prologue if necessary. */
- for (i = 0; i < expanded.nelts; ++i)
- skip_prologue_sal (&expanded.sals[i]);
-
- do_cleanups (old_chain);
-
- if (expanded.nelts <= 1)
- {
- /* This is an ugly workaround. If we get zero expanded sals
- then something is really wrong. Fix that by returning the
- original sal. */
-
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- return expanded;
- }
-
- if (original_pc)
- {
- found = 0;
- for (i = 0; i < expanded.nelts; ++i)
- if (expanded.sals[i].pc == original_pc)
- {
- found = 1;
- break;
- }
- gdb_assert (found);
- }
-
- return expanded;
-}
-
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
@@ -7499,7 +7368,6 @@ expand_line_sal_maybe (struct symtab_and_line sal)
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals,
struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
@@ -7508,17 +7376,30 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
int enabled, int internal)
{
int i;
+ struct linespec_sals *lsal;
- for (i = 0; i < sals.nelts; ++i)
+ if (canonical->pre_expanded)
+ gdb_assert (VEC_length (linespec_sals, canonical->sals) == 1);
+
+ for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
{
- struct symtabs_and_lines expanded =
- expand_line_sal_maybe (sals.sals[i]);
+ /* Note that 'addr_string' can be NULL in the case of a plain
+ 'break', without arguments. */
+ char *addr_string = (canonical->addr_string
+ ? xstrdup (canonical->addr_string)
+ : NULL);
+ char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
+ struct cleanup *inner = make_cleanup (xfree, addr_string);
- create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
+ make_cleanup (xfree, filter_string);
+ create_breakpoint_sal (gdbarch, lsal->sals,
+ addr_string,
+ filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
canonical->special_display);
+ discard_cleanups (inner);
}
}
@@ -7532,7 +7413,6 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (char **address,
- struct symtabs_and_lines *sals,
struct linespec_result *canonical)
{
char *addr_start = *address;
@@ -7544,10 +7424,11 @@ parse_breakpoint_sals (char **address,
{
if (default_breakpoint_valid)
{
+ struct linespec_sals lsal;
struct symtab_and_line sal;
init_sal (&sal); /* Initialize to zeroes. */
- sals->sals = (struct symtab_and_line *)
+ lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
sal.pc = default_breakpoint_address;
sal.line = default_breakpoint_line;
@@ -7562,8 +7443,11 @@ parse_breakpoint_sals (char **address,
with the same symtab and line. */
sal.explicit_pc = 1;
- sals->sals[0] = sal;
- sals->nelts = 1;
+ lsal.sals.sals[0] = sal;
+ lsal.sals.nelts = 1;
+ lsal.canonical = NULL;
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
else
error (_("No default breakpoint address now."));
@@ -7573,37 +7457,17 @@ parse_breakpoint_sals (char **address,
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving default_breakpoint_* alone.
-
- ObjC: However, don't match an Objective-C method name which
- may have a '+' or '-' succeeded by a '[' */
+ time while leaving default_breakpoint_* alone. */
struct symtab_and_line cursal = get_current_source_symtab_and_line ();
- if (default_breakpoint_valid
- && (!cursal.symtab
- || ((strchr ("+-", (*address)[0]) != NULL)
- && ((*address)[1] != '['))))
- *sals = decode_line_1 (address, 1, default_breakpoint_symtab,
- default_breakpoint_line, canonical);
+ if (default_breakpoint_valid)
+ decode_line_full (address, 1, default_breakpoint_symtab,
+ default_breakpoint_line, canonical,
+ NULL, NULL);
else
- *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- canonical);
- }
- /* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && canonical->canonical == NULL)
- canonical->canonical = xcalloc (sals->nelts, sizeof (char *));
- if (addr_start != (*address))
- {
- int i;
-
- for (i = 0; i < sals->nelts; i++)
- {
- /* Add the string if not present. */
- if (canonical->canonical[i] == NULL)
- canonical->canonical[i] = savestring (addr_start,
- (*address) - addr_start);
- }
+ decode_line_full (address, 1, (struct symtab *) NULL, 0,
+ canonical, NULL, NULL);
}
}
@@ -7638,15 +7502,20 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
for (i = 0; i < sals->nelts; i++)
{
+ struct gdbarch *sarch;
+
sal = &sals->sals[i];
- rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ sarch = get_sal_arch (*sal);
+ if (sarch == NULL)
+ sarch = gdbarch;
+ rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
NULL, &msg);
old_chain = make_cleanup (xfree, msg);
if (!rslt)
error (_("May not have a fast tracepoint at 0x%s%s"),
- paddress (gdbarch, sal->pc), (msg ? msg : ""));
+ paddress (sarch, sal->pc), (msg ? msg : ""));
do_cleanups (old_chain);
}
@@ -7788,8 +7657,6 @@ create_breakpoint (struct gdbarch *gdbarch,
int from_tty, int enabled, int internal)
{
volatile struct gdb_exception e;
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
char *copy_arg;
char *addr_start = arg;
struct linespec_result canonical;
@@ -7802,26 +7669,26 @@ create_breakpoint (struct gdbarch *gdbarch,
gdb_assert (ops != NULL);
- sals.sals = NULL;
- sals.nelts = 0;
init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
int i;
+ struct linespec_sals lsal;
- sals = decode_static_tracepoint_spec (&arg);
+ lsal.sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
- for (i = 0; i < sals.nelts; i++)
- canonical.canonical[i] = xstrdup (copy_arg);
+
+ lsal.canonical = xstrdup (copy_arg);
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+
goto done;
}
TRY_CATCH (e, RETURN_MASK_ALL)
{
- parse_breakpoint_sals (&arg, &sals, &canonical);
+ parse_breakpoint_sals (&arg, &canonical);
}
/* If caller is interested in rc value from parse, set value. */
@@ -7853,35 +7720,31 @@ create_breakpoint (struct gdbarch *gdbarch,
a pending breakpoint and selected yes, or pending
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
- copy_arg = xstrdup (addr_start);
- canonical.canonical = ©_arg;
- sals.nelts = 1;
- sals.sals = &pending_sal;
- pending_sal.pc = 0;
- pending = 1;
+ {
+ struct linespec_sals lsal;
+
+ copy_arg = xstrdup (addr_start);
+ lsal.canonical = xstrdup (copy_arg);
+ lsal.sals.nelts = 1;
+ lsal.sals.sals = XNEW (struct symtab_and_line);
+ init_sal (&lsal.sals.sals[0]);
+ pending = 1;
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+ }
break;
default:
throw_exception (e);
}
break;
default:
- if (!sals.nelts)
+ if (VEC_empty (linespec_sals, canonical.sals))
return 0;
}
done:
/* Create a chain of things that always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- if (!pending)
- {
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the canonical array but not its contents. */
- make_cleanup (xfree, canonical.canonical);
- }
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
@@ -7889,28 +7752,36 @@ create_breakpoint (struct gdbarch *gdbarch,
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the canonical for cleanup. These go on
- the bkpt_chain and only occur if the breakpoint create fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (canonical.canonical[i] != NULL)
- make_cleanup (xfree, canonical.canonical[i]);
- }
-
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ breakpoint_sals_to_pc (&iter->sals);
+ }
/* Fast tracepoints may have additional restrictions on location. */
if (type_wanted == bp_fast_tracepoint)
- check_fast_tracepoint_sals (gdbarch, &sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ check_fast_tracepoint_sals (gdbarch, &iter->sals);
+ }
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
if (!pending)
{
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+
if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
@@ -7919,7 +7790,7 @@ create_breakpoint (struct gdbarch *gdbarch,
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
&thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
@@ -7941,24 +7812,26 @@ create_breakpoint (struct gdbarch *gdbarch,
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (canonical.canonical[0]))
+ && is_marker_spec (lsal->canonical))
{
int i;
- for (i = 0; i < sals.nelts; ++i)
+ for (i = 0; i < lsal->sals.nelts; ++i)
{
struct symtabs_and_lines expanded;
struct tracepoint *tp;
struct cleanup *old_chain;
+ char *addr_string;
expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sals.sals[i];
- old_chain = make_cleanup (xfree, expanded.sals);
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical.addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
- canonical.canonical[i],
+ addr_string, NULL,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
@@ -7974,11 +7847,11 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, &tp->base);
- do_cleanups (old_chain);
+ discard_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
+ create_breakpoints_sal (gdbarch, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
@@ -7993,7 +7866,7 @@ create_breakpoint (struct gdbarch *gdbarch,
b = set_raw_breakpoint_without_location (type_wanted, ops);
set_breakpoint_number (internal, b);
b->thread = -1;
- b->addr_string = canonical.canonical[0];
+ b->addr_string = copy_arg;
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
@@ -8010,7 +7883,7 @@ create_breakpoint (struct gdbarch *gdbarch,
observer_notify_breakpoint_created (b);
}
- if (sals.nelts > 1)
+ if (VEC_length (linespec_sals, canonical.sals) > 1)
{
warning (_("Multiple breakpoints were set.\nUse the "
"\"delete\" command to delete unwanted breakpoints."));
@@ -8391,8 +8264,8 @@ break_range_command (char *arg, int from_tty)
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
- struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
+ struct linespec_sals *lsal_start, *lsal_end;
/* We don't support software ranged breakpoints. */
if (target_ranged_break_num_registers () < 0)
@@ -8405,71 +8278,58 @@ break_range_command (char *arg, int from_tty)
if (can_use_bp < 0)
error (_("Hardware breakpoints used exceeds limit."));
+ arg = skip_spaces (arg);
if (arg == NULL || arg[0] == '\0')
error(_("No address range specified."));
- sals_start.sals = NULL;
- sals_start.nelts = 0;
init_linespec_result (&canonical_start);
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ parse_breakpoint_sals (&arg, &canonical_start);
- parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
-
- sal_start = sals_start.sals[0];
- addr_string_start = canonical_start.canonical[0];
- cleanup_bkpt = make_cleanup (xfree, addr_string_start);
- xfree (sals_start.sals);
- xfree (canonical_start.canonical);
+ cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
if (arg[0] != ',')
error (_("Too few arguments."));
- else if (sals_start.nelts == 0)
+ else if (VEC_empty (linespec_sals, canonical_start.sals))
error (_("Could not find location of the beginning of the range."));
- else if (sals_start.nelts != 1)
+
+ lsal_start = VEC_index (linespec_sals, canonical_start.sals, 0);
+
+ if (VEC_length (linespec_sals, canonical_start.sals) > 1
+ || lsal_start->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_start);
+ sal_start = lsal_start->sals.sals[0];
+ addr_string_start = lsal_start->canonical;
arg++; /* Skip the comma. */
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ arg = skip_spaces (arg);
/* Parse the end location. */
- sals_end.sals = NULL;
- sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
- /* We call decode_line_1 directly here instead of using
+ /* We call decode_line_full directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
- sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
- &canonical_end);
-
- /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
- if (canonical_end.canonical == NULL)
- canonical_end.canonical = xcalloc (1, sizeof (char *));
- /* Add the string if not present. */
- if (arg_start != arg && canonical_end.canonical[0] == NULL)
- canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
-
- sal_end = sals_end.sals[0];
- addr_string_end = canonical_end.canonical[0];
- make_cleanup (xfree, addr_string_end);
- xfree (sals_end.sals);
- xfree (canonical_end.canonical);
-
- if (sals_end.nelts == 0)
+ decode_line_full (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end, NULL, NULL);
+
+ make_cleanup_destroy_linespec_result (&canonical_end);
+
+ if (VEC_empty (linespec_sals, canonical_end.sals))
error (_("Could not find location of the end of the range."));
- else if (sals_end.nelts != 1)
+
+ lsal_end = VEC_index (linespec_sals, canonical_end.sals, 0);
+ if (VEC_length (linespec_sals, canonical_end.sals) > 1
+ || lsal_end->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_end);
+ sal_end = lsal_end->sals.sals[0];
+ addr_string_end = lsal_end->canonical;
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
@@ -8496,11 +8356,11 @@ break_range_command (char *arg, int from_tty)
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
- b->addr_string = addr_string_start;
- b->addr_string_range_end = addr_string_end;
+ b->addr_string = xstrdup (addr_string_start);
+ b->addr_string_range_end = xstrdup (addr_string_end);
b->loc->length = length;
- discard_cleanups (cleanup_bkpt);
+ do_cleanups (cleanup_bkpt);
mention (b);
observer_notify_breakpoint_created (b);
@@ -9608,9 +9468,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
if (default_breakpoint_valid)
sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
- default_breakpoint_line, NULL);
+ default_breakpoint_line);
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
@@ -10192,18 +10052,21 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
- && (loc->pspace == sal.pspace)
- && (loc->address == sal.pc)
- && (!section_is_overlay (loc->section)
- || loc->section == sal.section);
- int line_match = ((default_match || (0 == sal.pc))
- && b->source_file != NULL
+ /* If the user specified file:line, don't allow a PC
+ match. This matches historical gdb behavior. */
+ int pc_match = (!sal.explicit_line
+ && sal.pc
+ && (loc->pspace == sal.pspace)
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section));
+ int line_match = ((default_match || sal.explicit_line)
+ && loc->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && filename_cmp (b->source_file,
+ && filename_cmp (loc->source_file,
sal.symtab->filename) == 0
- && b->line_number == sal.line);
+ && loc->line_number == sal.line);
if (pc_match || line_match)
{
match = 1;
@@ -10739,15 +10602,25 @@ say_where (struct breakpoint *b)
}
else
{
- if (opts.addressprint || b->source_file == NULL)
+ if (opts.addressprint || b->loc->source_file == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
if (b->loc->next)
{
@@ -10767,6 +10640,7 @@ bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
xfree (self->function_name);
+ xfree (self->source_file);
}
static const struct bp_location_ops bp_location_ops =
@@ -10783,8 +10657,8 @@ base_breakpoint_dtor (struct breakpoint *self)
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
xfree (self->addr_string);
+ xfree (self->filter);
xfree (self->addr_string_range_end);
- xfree (self->source_file);
}
static struct bp_location *
@@ -11615,17 +11489,18 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
ui_out_field_int (uiout, "line", sal.line);
ui_out_text (uiout, "\n");
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
- xfree (b->source_file);
+ xfree (b->loc->source_file);
if (sym)
- b->source_file = xstrdup (sal.symtab->filename);
+ b->loc->source_file = xstrdup (sal.symtab->filename);
else
- b->source_file = NULL;
+ b->loc->source_file = NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal.symtab->filename, b->line_number);
+ sal.symtab->filename,
+ b->loc->line_number);
/* Might be nice to check if function changed, and warn if
so. */
@@ -11675,8 +11550,17 @@ update_breakpoint_locations (struct breakpoint *b,
int i;
struct bp_location *existing_locations = b->loc;
- /* Ranged breakpoints have only one start location and one end location. */
- gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+ if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
+ {
+ /* Ranged breakpoints have only one start location and one end
+ location. */
+ b->enable_state = bp_disabled;
+ update_global_location_list (1);
+ printf_unfiltered (_("Could not reset ranged breakpoint %d: "
+ "multiple locations found\n"),
+ b->number);
+ return;
+ }
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
@@ -11691,8 +11575,11 @@ update_breakpoint_locations (struct breakpoint *b,
for (i = 0; i < sals.nelts; ++i)
{
- struct bp_location *new_loc =
- add_location_to_breakpoint (b, &(sals.sals[i]));
+ struct bp_location *new_loc;
+
+ switch_to_program_space_and_thread (sals.sals[i].pspace);
+
+ new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
/* Reparse conditions, they might contain references to the
old symtab. */
@@ -11716,16 +11603,6 @@ update_breakpoint_locations (struct breakpoint *b,
}
}
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sals.sals[i].symtab->filename);
-
- if (b->line_number == 0)
- b->line_number = sals.sals[i].line;
-
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
@@ -11792,7 +11669,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
char *s;
int marker_spec;
struct symtabs_and_lines sals = {0};
- struct gdb_exception e;
+ volatile struct gdb_exception e;
s = addr_string;
marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
@@ -11813,7 +11690,30 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
error (_("marker %s not found"), tp->static_trace_marker_id);
}
else
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ {
+ struct linespec_result canonical;
+
+ init_linespec_result (&canonical);
+ decode_line_full (&s, 1, (struct symtab *) NULL, 0,
+ &canonical, multiple_symbols_all,
+ b->filter);
+
+ /* We should get 0 or 1 resulting SALs. */
+ gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
+
+ if (VEC_length (linespec_sals, canonical.sals) > 0)
+ {
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ sals = lsal->sals;
+ /* Arrange it so the destructor does not free the
+ contents. */
+ lsal->sals.sals = NULL;
+ }
+
+ destroy_linespec_result (&canonical);
+ }
}
if (e.reason < 0)
{
@@ -11846,9 +11746,10 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
{
- gdb_assert (sals.nelts == 1);
+ int i;
- resolve_sal_pc (&sals.sals[0]);
+ for (i = 0; i < sals.nelts; ++i)
+ resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
char *cond_string = 0;
@@ -11891,7 +11792,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals.sals);
- expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = sals;
}
if (b->addr_string_range_end)
@@ -11900,7 +11801,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals_end.sals);
- expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ expanded_end = sals_end;
}
}
@@ -12434,11 +12335,10 @@ decode_line_spec_1 (char *string, int funfirstline)
if (default_breakpoint_valid)
sals = decode_line_1 (&string, funfirstline,
default_breakpoint_symtab,
- default_breakpoint_line,
- NULL);
+ default_breakpoint_line);
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, NULL);
+ (struct symtab *) NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e038999..e5b8422 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -393,6 +393,14 @@ struct bp_location
This variable keeps a number of events still to go, when
it becomes 0 this location is retired. */
int events_till_retirement;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ char *source_file;
};
/* This structure is a collection of function pointers that, if available,
@@ -540,14 +548,6 @@ struct breakpoint
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
- /* Line number of this address. */
-
- int line_number;
-
- /* Source file name of this address. */
-
- char *source_file;
-
/* Non-zero means a silent breakpoint (don't print frame info
if we stop here). */
unsigned char silent;
@@ -571,6 +571,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
+ /* The filter that should be passed to decode_line_full when
+ re-setting this breakpoint. This may be NULL, but otherwise is
+ allocated with xmalloc. */
+ char *filter;
+
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 624d0de..2b827a0 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -92,6 +92,9 @@ void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
@@ -244,16 +247,6 @@ help_command (char *command, int from_tty)
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
@@ -794,8 +787,9 @@ edit_command (char *arg, int from_tty)
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
@@ -924,8 +918,9 @@ list_command (char *arg, int from_tty)
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
@@ -957,9 +952,10 @@ list_command (char *arg, int from_tty)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals_end = decode_line_list (&arg1, 0, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ sals_end = decode_line_list (&arg1, 0, sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
@@ -1470,6 +1466,85 @@ ambiguous_line_spec (struct symtabs_and_lines *sals)
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ || sals->sals[i].symtab == NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
diff --git a/gdb/defs.h b/gdb/defs.h
index d0b6813..0e6e629 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -428,6 +428,7 @@ char *ldirname (const char *filename);
char **gdb_buildargv (const char *);
int compare_positive_ints (const void *ap, const void *bp);
+int compare_strings (const void *ap, const void *bp);
/* A wrapper for bfd_errmsg to produce a more helpful error message
in the case of bfd_error_file_ambiguously recognized.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8a7d7e9..7547a40 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -443,9 +443,6 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
return sym;
}
-/* Define VEC (CORE_ADDR) functions. */
-DEF_VEC_I (CORE_ADDR);
-
/* Verify function with entry point exact address ADDR can never call itself
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
can call itself via tail calls.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 84eb589..145c8d0 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2438,10 +2438,38 @@ dw2_forget_cached_source_info (struct objfile *objfile)
dw2_free_cached_file_names, NULL);
}
+/* Helper function for dw2_map_symtabs_matching_filename that expands
+ the symtabs and calls the iterator. */
+
+static int
+dw2_map_expand_apply (struct objfile *objfile,
+ struct dwarf2_per_cu_data *per_cu,
+ const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded CUs. */
+ if (per_cu->v.quick->symtab)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ dw2_instantiate_symtab (objfile, per_cu);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
static int
-dw2_lookup_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
+dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
{
int i;
int check_basename = lbasename (name) == name;
@@ -2469,8 +2497,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (FILENAME_CMP (name, this_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
if (check_basename && ! base_cu
@@ -2485,8 +2515,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (full_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
@@ -2498,8 +2530,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
}
@@ -2507,8 +2541,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (base_cu)
{
- *result = dw2_instantiate_symtab (objfile, base_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, base_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
return 0;
@@ -2850,7 +2886,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
- dw2_lookup_symtab,
+ dw2_map_symtabs_matching_filename,
dw2_lookup_symbol,
dw2_pre_expand_symtabs_matching,
dw2_print_stats,
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 37ec368..f8ffe46 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -44,108 +44,246 @@
#include <ctype.h>
#include "cli/cli-utils.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_variable (struct linespec_state *self,
+ char *copy);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symtab *symtab_from_filename (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 symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+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_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+/* Helper functions. */
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Add SAL to SALS. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+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 decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* 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 symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+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);
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+ if (self->canonical)
+ {
+ char *canonical_name = NULL;
-/* Helper functions. */
+ self->canonical_names = xrealloc (self->canonical_names,
+ sals->nelts * sizeof (char *));
+ if (sal->symtab && sal->symtab->filename)
+ {
+ char *filename = sal->symtab->filename;
+
+ /* FIXME: this is where we should do "FILE:FUNCTION:LINE",
+ to let us distinguish between different template
+ instantiations. */
+ 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
@@ -180,26 +318,62 @@ 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 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 (strcmp_iw (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;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ set_current_program_space (pspace);
- return count;
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+ iterate_name_matcher,
+ ALL_DOMAIN,
+ &name);
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ iterate_over_symbols (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -226,40 +400,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);
@@ -287,181 +445,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;
-}
-
-/* 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;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-/* 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 ','
@@ -517,147 +526,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
{
@@ -665,14 +681,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". */
@@ -812,13 +824,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
@@ -835,21 +844,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);
@@ -876,7 +890,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)
@@ -902,10 +923,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? */
@@ -933,14 +956,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);
@@ -953,12 +978,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. */
@@ -973,9 +1002,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. */
@@ -998,10 +1028,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). */
@@ -1041,90 +1076,232 @@ 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;
+ }
}
-\f
+/* A constructor for linespec_state. */
-/* 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. */
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int funfirstline,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = funfirstline;
+ 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);
+}
-/* First, some functions to initialize stuff at the beggining of the
- function. */
+/* A destructor for linespec_state. */
static void
-initialize_defaults (struct symtab **default_symtab, int *default_line)
+linespec_state_destructor (void *arg)
{
- if (*default_symtab == 0)
- {
- /* Use whatever we have for the default source line. We don't use
- get_current_or_default_symtab_and_line as it can recurse and call
- us back! */
- struct symtab_and_line cursal =
- get_current_source_symtab_and_line ();
-
- *default_symtab = cursal.symtab;
- *default_line = cursal.line;
- }
-}
+ struct linespec_state *self = arg;
-\f
+ xfree (self->user_filename);
+ xfree (self->user_function);
+ VEC_free (symtab_p, self->file_symtabs);
+ htab_delete (self->addr_set);
+}
-/* Decode arg of the form *PC. */
+/* See linespec.h. */
-static struct symtabs_and_lines
-decode_indirect (char **argptr)
+void
+decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter)
{
- struct symtabs_and_lines values;
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+ char *arg_start = *argptr;
+
+ 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);
+
+ linespec_state_constructor (&state, funfirstline, 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;
+
+ 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)
+ {
+ VEC (const_char_ptr) *filters = 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 funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, 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;
+}
+
+/* See linespec.h. */
+
+struct symtabs_and_lines
+decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, default_symtab,
+ default_line, NULL);
+ state.list_mode = 1;
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+\f
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+decode_indirect (struct linespec_state *self, char **argptr)
+{
+ struct symtabs_and_lines values;
CORE_ADDR pc;
+ char *initial = *argptr;
(*argptr)++;
pc = value_as_address (parse_to_comma_and_eval (argptr));
@@ -1138,6 +1315,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;
}
@@ -1235,8 +1415,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)
@@ -1264,94 +1443,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
+ if (self->canonical)
{
- 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
- {
- /* 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,
- ¤t_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
@@ -1360,9 +1497,8 @@ 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;
@@ -1370,10 +1506,9 @@ decode_compound (char **argptr, int funfirstline,
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. */
@@ -1509,15 +1644,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
@@ -1567,9 +1701,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. */
@@ -1579,8 +1711,10 @@ 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. */
@@ -1600,7 +1734,6 @@ decode_compound (char **argptr, int funfirstline,
/* Look up entire name. */
name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
@@ -1608,29 +1741,51 @@ decode_compound (char **argptr, int funfirstline,
make_cleanup (xfree, name);
}
- 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;
+ return decode_variable (self, copy);
+}
- /* 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);
- }
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* 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);
-}
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
+
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
+
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
+
+ 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
@@ -1639,182 +1794,338 @@ decode_compound (char **argptr, int funfirstline,
lookup_symbol 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;
+
+ set_current_program_space (SYMTAB_PSPACE (elt));
+ search_block = get_search_block (elt);
+ iterate_over_symbols (search_block, copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ 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;
- /* Find all methods with a matching name, and put them in
- sym_arr. */
+ uia = (uintptr_t) *sa;
+ uib = (uintptr_t) *sb;
- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
- file_symtab);
+ if (uia < uib)
+ return -1;
+ if (uia > uib)
+ return 1;
+
+ return 0;
+}
- /* 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)
+/* 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);
+}
+
+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);
+
+ 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
+ passing to lookup_symbol. */
+ 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;
+
+ 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);
+}
+
+\f
+
+/* 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;
}
-\f
+/* 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);
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+ /* Find that file's data. */
+ ALL_PSPACES (pspace)
+ {
+ set_current_program_space (pspace);
+ iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+ }
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+ 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 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] == '"')
@@ -1823,9 +2134,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,
@@ -1836,31 +2147,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);
+
+ 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 file_symtab;
+ 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] == '"')
@@ -1869,18 +2196,39 @@ 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 looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (VEC_empty (symbolp, result))
+ {
+ struct symbol *function_symbol;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ xfree (copy);
+ copy = xstrdup (SYMBOL_SEARCH_NAME (function_symbol));
+ *user_function = copy;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols,
+ &result, NULL);
+ }
+ }
+
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ return result;
}
\f
@@ -1890,13 +2238,16 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
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 ix;
+ struct symtab *elt;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1904,12 +2255,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
@@ -1917,11 +2265,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 == '+')
@@ -1934,14 +2290,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;
@@ -1949,28 +2305,77 @@ 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);
+
+ 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));
+
+ if (self->list_mode)
+ {
+ /* 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);
+ }
+ else
+ {
+ int pcix;
+ CORE_ADDR pc;
+ VEC (CORE_ADDR) *pcs;
+
+ pcs = find_pcs_for_symtab_line (elt, val.line);
+ if (VEC_empty (CORE_ADDR, pcs))
+ continue;
+
+ for (pcix = 0; VEC_iterate (CORE_ADDR, pcs, pcix, pc); ++pcix)
+ {
+ val.symtab = elt;
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = pc;
+ val.explicit_line = 1;
+
+ skip_prologue_sal (&val);
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
+
+ VEC_free (CORE_ADDR, pcs);
+ }
+ }
+
+ 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;
}
@@ -1979,17 +2384,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')
@@ -2011,19 +2416,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;
- /* 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);
+ TRY_CATCH (exc, RETURN_MASK_ERROR)
+ {
+ values = decode_variable (self, copy);
+ }
+
+ if (exc.reason == 0)
+ return values;
+
+ 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))
@@ -2033,18 +2437,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));
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ /* Either history value or convenience value from above, in valx. */
+ val.symtab = elt;
+ val.line = valx;
+ val.pc = 0;
+ val.pspace = elt ? SYMTAB_PSPACE (elt) : current_program_space;
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
+
+ if (self->canonical)
+ {
+ self->canonical->pre_expanded = 1;
+ if (self->user_filename)
+ self->canonical->addr_string = xstrprintf ("%s:%s",
+ self->user_filename, copy);
+ else
+ self->canonical->addr_string = xstrdup (copy);
+ }
return values;
}
@@ -2053,7 +2476,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.
@@ -2062,78 +2485,296 @@ 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)
{
+ 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_selected_block (0);
+
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;
+ }
+
+ 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)
+ {
+ 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;
+
+ 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
+ && !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, ¤t_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 (maybe_add_address (info->state->addr_set, info->objfile->pspace,
+ SYMBOL_VALUE_ADDRESS (minsym)))
+ minsym_found (info->state, info->objfile, minsym, &info->result);
+}
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+/* Search minimal symbols in all objfiles for NAME. If SEARCH_PSPACE
+ is not NULL, the search is restricted to just that program
+ space. */
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+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;
- return sym != NULL;
+ 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))
+ {
+ set_current_program_space (SYMTAB_PSPACE (elt));
+ 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);
+ 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);
+
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
- name = canon;
- make_cleanup (xfree, name);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (sym != NULL)
+ /* If looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (info.result.nelts == 0)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
- }
+ struct symbol *function_symbol;
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ function_symbol = lookup_symbol (lookup_name, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ copy = SYMBOL_SEARCH_NAME (function_symbol);
+ add_matching_symbols_to_info (copy, &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);
}
@@ -2142,130 +2783,81 @@ 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;
}
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,
- ¤t_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;
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+ 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);
+}
- values.nelts = 1;
- return values;
+/* Cleanup function for a linespec_result. */
+
+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);
}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 3c86af3..bd9fa14 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -20,6 +20,25 @@
struct symtab;
+#include "vec.h"
+
+/* decode_line_full returns a vector of these. */
+
+struct linespec_sals
+{
+ /* This is the linespec corresponding to the sals contained in this
+ object. It can be passed as the FILTER argument to future calls
+ to decode_line_full. It is allocated with xmalloc and the caller
+ is responsible for freeing it. */
+ char *canonical;
+
+ /* Sals. */
+ struct symtabs_and_lines sals;
+};
+
+typedef struct linespec_sals linespec_sals;
+DEF_VEC_O (linespec_sals);
+
/* An instance of this may be filled in by decode_line_1. The caller
must call init_linespec_result to initialize it. */
@@ -30,22 +49,85 @@ struct linespec_result
display mechanism would do the wrong thing. */
int special_display;
- /* If non-NULL, an array of canonical names for returned
- symtab_and_line objects. The array has as many elements as the
- `nelts' field in the symtabs_and_line returned by decode_line_1.
- An element in the array may be NULL. The array and each non-NULL
- element in it are allocated with xmalloc and must be freed by the
- caller. */
- char **canonical;
+ /* If non-zero, the linespec result should be considered to be a
+ "pre-expanded" multi-location linespec. A pre-expanded linespec
+ holds all matching locations in a single linespec_sals
+ object. */
+ int pre_expanded;
+
+ /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+ by the user. This is allocated with xmalloc and the caller is
+ responsible for freeing it. */
+ char *addr_string;
+
+ /* The sals. The vector should be freed by the caller. */
+ VEC (linespec_sals) *sals;
};
/* Initialize a linespec_result. */
extern void init_linespec_result (struct linespec_result *);
+/* Destroy a linespec_result. */
+
+extern void destroy_linespec_result (struct linespec_result *);
+
+/* Return a cleanup that destroys a linespec_result. */
+
+extern struct cleanup *
+ make_cleanup_destroy_linespec_result (struct linespec_result *);
+
extern struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline,
- struct symtab *default_symtab, int default_line,
- struct linespec_result *canonical);
+ struct symtab *default_symtab, int default_line);
+
+/* Like decode_line_1, but useful only for the 'list' command. With
+ this variant, a "file:line" linespec will always return a result. */
+
+extern struct symtabs_and_lines
+ decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line);
+
+/* Parse *ARGPTR as a linespec and return results. This is the "full"
+ interface to this module, which handles multiple results
+ properly.
+
+ FUNFIRSTLINE is nonzero if we want the resulting SALs to describe
+ the first line of indicated functions.
+
+ DEFAULT_SYMTAB and DEFAULT_LINE describe the default location.
+ DEFAULT_SYMTAB can be NULL, in which case the current symtab and
+ line are used.
+
+ CANONICAL is where the results are stored. It must not be NULL.
+
+ SELECT_MODE must be one of the multiple_symbols_* constants, or
+ NULL. It determines how multiple results will be handled. If
+ NULL, the appropriate CLI value will be used.
+
+ FILTER can either be NULL or a string holding a canonical name.
+ This is only valid when SELECT_MODE is multiple_symbols_all.
+
+ Multiple results are handled differently depending on the
+ arguments:
+
+ . With multiple_symbols_cancel, an exception is thrown.
+
+ . With multiple_symbols_ask, a menu is presented to the user. The
+ user may select none, in which case an exception is thrown; or all,
+ which is handled like multiple_symbols_all, below. Otherwise,
+ CANONICAL->SALS will have one entry for each name the user chose.
+
+ . With multiple_symbols_all, CANONICAL->SALS will have a single
+ entry describing all the matching locations. If FILTER is
+ non-NULL, then only locations whose canonical name is equal (in the
+ strcmp sense) to FILTER will be returned; all others will be
+ filtered out. */
+
+extern void decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter);
#endif /* defined (LINESPEC_H) */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 70871cd..f90f036 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -310,6 +310,46 @@ lookup_minimal_symbol (const char *name, const char *sfile,
return NULL;
}
+/* Iterate over all the minimal symbols in the objfile OBJF which
+ match NAME. Both the ordinary and demangled names of each symbol
+ are considered. The caller is responsible for canonicalizing NAME,
+ should that need to be done.
+
+ For each matching symbol, CALLBACK is called with the symbol and
+ USER_DATA as arguments. */
+
+void
+iterate_over_minimal_symbols (struct objfile *objf, const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data)
+{
+ unsigned int hash;
+ struct minimal_symbol *iter;
+ int (*cmp) (const char *, const char *);
+
+ /* The first pass is over the ordinary hash table. */
+ hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_hash[hash];
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+ while (iter)
+ {
+ if (cmp (SYMBOL_LINKAGE_NAME (iter), name) == 0)
+ (*callback) (iter, user_data);
+ iter = iter->hash_next;
+ }
+
+ /* The second pass is over the demangled table. */
+ hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_demangled_hash[hash];
+ while (iter)
+ {
+ if (SYMBOL_MATCHES_SEARCH_NAME (iter, name))
+ (*callback) (iter, user_data);
+ iter = iter->demangled_hash_next;
+ }
+}
+
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a pointer
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 592b52e..dcf9459 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -952,49 +952,7 @@ classes_info (char *regexp, int from_tty)
printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
-/*
- * Function: find_imps (char *selector, struct symbol **sym_arr)
- *
- * Input: a string representing a selector
- * a pointer to an array of symbol pointers
- * possibly a pointer to a symbol found by the caller.
- *
- * Output: number of methods that implement that selector. Side
- * effects: The array of symbol pointers is filled with matching syms.
- *
- * By analogy with function "find_methods" (symtab.c), builds a list
- * of symbols matching the ambiguous input, so that "decode_line_2"
- * (symtab.c) can list them and ask the user to choose one or more.
- * In this case the matches are objective c methods
- * ("implementations") matching an objective c selector.
- *
- * Note that it is possible for a normal (c-style) function to have
- * the same name as an objective c selector. To prevent the selector
- * from eclipsing the function, we allow the caller (decode_line_1) to
- * search for such a function first, and if it finds one, pass it in
- * to us. We will then integrate it into the list. We also search
- * for one here, among the minsyms.
- *
- * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
- * into two parts: debuggable (struct symbol) syms, and
- * non_debuggable (struct minimal_symbol) syms. The debuggable
- * ones will come first, before NUM_DEBUGGABLE (which will thus
- * be the index of the first non-debuggable one).
- */
-
-/*
- * Function: total_number_of_imps (char *selector);
- *
- * Input: a string representing a selector
- * Output: number of methods that implement that selector.
- *
- * By analogy with function "total_number_of_methods", this allows
- * decode_line_1 (symtab.c) to detect if there are objective c methods
- * matching the input, and to allocate an array of pointers to them
- * which can be manipulated by "decode_line_2" (also in symtab.c).
- */
-
-char *
+static char *
parse_selector (char *method, char **selector)
{
char *s1 = NULL;
@@ -1050,7 +1008,7 @@ parse_selector (char *method, char **selector)
return s2;
}
-char *
+static char *
parse_method (char *method, char *type, char **class,
char **category, char **selector)
{
@@ -1154,15 +1112,11 @@ parse_method (char *method, char *type, char **class,
}
static void
-find_methods (struct symtab *symtab, char type,
- const char *class, const char *category,
- const char *selector, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+find_methods (char type, const char *class, const char *category,
+ const char *selector,
+ VEC (const_char_ptr) **symbol_names)
{
struct objfile *objfile = NULL;
- struct minimal_symbol *msymbol = NULL;
- struct block *block = NULL;
- struct symbol *sym = NULL;
char *symname = NULL;
@@ -1171,21 +1125,15 @@ find_methods (struct symtab *symtab, char type,
char *ncategory = NULL;
char *nselector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
static char *tmp = NULL;
static unsigned int tmplen = 0;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
-
- if (symtab)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ gdb_assert (symbol_names != NULL);
ALL_OBJFILES (objfile)
{
unsigned int *objc_csym;
+ struct minimal_symbol *msymbol = NULL;
/* The objfile_csym variable counts the number of ObjC methods
that this objfile defines. We save that count as a private
@@ -1202,7 +1150,6 @@ find_methods (struct symtab *symtab, char type,
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
QUIT;
@@ -1216,18 +1163,8 @@ find_methods (struct symtab *symtab, char type,
/* Not a method name. */
continue;
- /* 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, pc,
- ¤t_target);
-
objfile_csym++;
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
/* Now that thinks are a bit sane, clean up the symname. */
while ((strlen (symname) + 1) >= tmplen)
{
@@ -1255,41 +1192,9 @@ find_methods (struct symtab *symtab, char type,
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
- sym = find_pc_function (pc);
- if (sym != NULL)
- {
- const char *newsymname = SYMBOL_NATURAL_NAME (sym);
-
- if (strcmp (symname, newsymname) == 0)
- {
- /* Found a high-level method sym: swap it into the
- lower part of sym_arr (below num_debuggable). */
- if (syms != NULL)
- {
- syms[csym] = syms[cdebug];
- syms[cdebug] = sym;
- }
- csym++;
- cdebug++;
- }
- else
- {
- warning (
-"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
- newsymname, symname);
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
- }
- else
- {
- /* Found a non-debuggable method symbol. */
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
+ VEC_safe_push (const_char_ptr, *symbol_names, symname);
}
+
if (objc_csym == NULL)
{
objc_csym = obstack_alloc (&objfile->objfile_obstack,
@@ -1301,38 +1206,79 @@ find_methods (struct symtab *symtab, char type,
/* Count of ObjC methods in this objfile should be constant. */
gdb_assert (*objc_csym == objfile_csym);
}
+}
+
+/* Uniquify a VEC of strings. */
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
+static void
+uniquify_strings (VEC (const_char_ptr) **strings)
+{
+ int ix;
+ const char *elem, *last = NULL;
+ int out;
+
+ qsort (VEC_address (const_char_ptr, *strings),
+ VEC_length (const_char_ptr, *strings),
+ sizeof (const_char_ptr),
+ compare_strings);
+ out = 0;
+ for (ix = 0; VEC_iterate (const_char_ptr, *strings, ix, elem); ++ix)
+ {
+ if (last == NULL || strcmp (last, elem) != 0)
+ {
+ /* Keep ELEM. */
+ VEC_replace (const_char_ptr, *strings, out, elem);
+ ++out;
+ }
+ last = elem;
+ }
+ VEC_truncate (const_char_ptr, *strings, out);
}
-char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+char *
+find_imps (char *method, VEC (const_char_ptr) **symbol_names)
{
char type = '\0';
char *class = NULL;
char *category = NULL;
char *selector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
- unsigned int ncsym = 0;
- unsigned int ncdebug = 0;
-
char *buf = NULL;
char *tmp = NULL;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
+ int selector_case = 0;
- if (nsym != NULL)
- *nsym = 0;
- if (ndebug != NULL)
- *ndebug = 0;
+ gdb_assert (symbol_names != NULL);
buf = (char *) alloca (strlen (method) + 1);
strcpy (buf, method);
@@ -1340,99 +1286,37 @@ char *find_imps (struct symtab *symtab, struct block *block,
if (tmp == NULL)
{
- struct symbol *sym = NULL;
- struct minimal_symbol *msym = NULL;
-
strcpy (buf, method);
tmp = parse_selector (buf, &selector);
if (tmp == NULL)
return NULL;
- sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
- if (sym != NULL)
- {
- if (syms)
- syms[csym] = sym;
- csym++;
- cdebug++;
- }
-
- if (sym == NULL)
- msym = lookup_minimal_symbol (selector, 0, 0);
-
- if (msym != NULL)
- {
- if (syms)
- syms[csym] = (struct symbol *)msym;
- csym++;
- }
+ selector_case = 1;
}
- if (syms != NULL)
- find_methods (symtab, type, class, category, selector,
- syms + csym, &ncsym, &ncdebug);
- else
- find_methods (symtab, type, class, category, selector,
- NULL, &ncsym, &ncdebug);
-
- /* If we didn't find any methods, just return. */
- if (ncsym == 0 && ncdebug == 0)
- return method;
+ find_methods (type, class, category, selector, symbol_names);
- /* Take debug symbols from the second batch of symbols and swap them
- * with debug symbols from the first batch. Repeat until either the
- * second section is out of debug symbols or the first section is
- * full of debug symbols. Either way we have all debug symbols
- * packed to the beginning of the buffer.
- */
-
- if (syms != NULL)
+ /* If we hit the "selector" case, and we found some methods, then
+ add the selector itself as a symbol, if it exists. */
+ if (selector_case && !VEC_empty (const_char_ptr, *symbol_names))
{
- while ((cdebug < csym) && (ncdebug > 0))
+ struct symbol *sym = lookup_symbol (selector, NULL, VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (sym));
+ else
{
- struct symbol *s = NULL;
- /* First non-debugging symbol. */
- unsigned int i = cdebug;
- /* Last of second batch of debug symbols. */
- unsigned int j = csym + ncdebug - 1;
-
- s = syms[j];
- syms[j] = syms[i];
- syms[i] = s;
-
- /* We've moved a symbol from the second debug section to the
- first one. */
- cdebug++;
- ncdebug--;
+ struct minimal_symbol *msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (msym));
}
}
- csym += ncsym;
- cdebug += ncdebug;
-
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
-
- if (syms == NULL)
- return method + (tmp - buf);
-
- if (csym > 1)
- {
- /* Sort debuggable symbols. */
- if (cdebug > 1)
- qsort (syms, cdebug, sizeof (struct minimal_symbol *),
- compare_classes);
-
- /* Sort minimal_symbols. */
- if ((csym - cdebug) > 1)
- qsort (&syms[cdebug], csym - cdebug,
- sizeof (struct minimal_symbol *), compare_classes);
- }
- /* Terminate the sym_arr list. */
- syms[csym] = 0;
+ uniquify_strings (symbol_names);
return method + (tmp - buf);
}
diff --git a/gdb/objc-lang.h b/gdb/objc-lang.h
index ee4cc29..351af7b 100644
--- a/gdb/objc-lang.h
+++ b/gdb/objc-lang.h
@@ -21,6 +21,8 @@
#if !defined(OBJC_LANG_H)
#define OBJC_LANG_H
+#include "cp-support.h" /* For VEC (const_char_ptr) */
+
struct stoken;
struct value;
@@ -39,15 +41,7 @@ extern char *objc_demangle (const char *mangled, int options);
extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
-extern char *parse_selector (char *method, char **selector);
-
-extern char *parse_method (char *method, char *type,
- char **class, char **category,
- char **selector);
-
-extern char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug);
+extern char *find_imps (char *method, VEC (const_char_ptr) **symbol_names);
extern struct value *value_nsstring (struct gdbarch *gdbarch,
char *ptr, int len);
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index fd8bb7d..7e74449 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -125,13 +125,42 @@ require_partial_symbols (struct objfile *objfile, int verbose)
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p)
-/* Lookup the partial symbol table of a source file named NAME.
- *If* there is no '/' in the name, a match after a '/'
- in the psymtab filename will also work. */
+/* Helper function for partial_map_symtabs_matching_filename that
+ expands the symtabs and calls the iterator. */
-static struct partial_symtab *
-lookup_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path)
+static int
+partial_map_expand_apply (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ struct partial_symtab *pst,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded psymtabs. */
+ if (pst->readin)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ psymtab_to_symtab (pst);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
+static int
+partial_map_symtabs_matching_filename (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data)
{
struct partial_symtab *pst;
@@ -139,7 +168,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
/* If the user gave us an absolute path, try to find the file in
@@ -150,7 +181,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
if (pst->fullname != NULL
&& FILENAME_CMP (full_path, pst->fullname) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
@@ -165,7 +198,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
}
if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
}
@@ -176,29 +211,12 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path, pst,
+ callback, data))
+ return 1;
}
- return (NULL);
-}
-
-static int
-lookup_symtab_via_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
-{
- struct partial_symtab *ps;
-
- ps = lookup_partial_symtab (objfile, name, full_path, real_path);
- if (!ps)
- return 0;
-
- if (ps->readin)
- error (_("Internal: readin %s pst for `%s' found when no symtab found."),
- ps->filename, name);
-
- *result = PSYMTAB_TO_SYMTAB (ps);
- return 1;
+ return 0;
}
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
@@ -1287,7 +1305,7 @@ const struct quick_symbol_functions psym_functions =
objfile_has_psyms,
find_last_source_symtab_from_partial,
forget_cached_source_info_partial,
- lookup_symtab_via_partial_symtab,
+ partial_map_symtabs_matching_filename,
lookup_symbol_aux_psymtabs,
pre_expand_symtabs_matching_psymtabs,
print_psymtab_stats_for_objfile,
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 585100d..07352d9 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -830,7 +830,7 @@ DEF_VEC_O (type_equality_entry_d);
the same, 0 otherwise. Handles NULLs properly. */
static int
-compare_strings (const char *s, const char *t)
+compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
@@ -866,9 +866,10 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
- if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
+ TYPE_TAG_NAME (type2)))
return Py_NE;
- if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
@@ -891,7 +892,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
- if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_NAME (*field1),
+ FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
@@ -905,8 +907,8 @@ check_types_equal (struct type *type1, struct type *type2,
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
- if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
- FIELD_STATIC_PHYSNAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
+ FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 3a5a6b5..0473242 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -502,7 +502,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
{
copy = xstrdup (arg);
make_cleanup (xfree, copy);
- sals = decode_line_1 (©, 0, 0, 0, 0);
+ sals = decode_line_1 (©, 0, 0, 0);
make_cleanup (xfree, sals.sals);
}
else
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 888aa34..21efbdf 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -28,8 +28,6 @@
#include "gdb_string.h"
-DEF_VEC_I(CORE_ADDR);
-
/* Private data for each loaded library. */
struct lm_info
{
diff --git a/gdb/source.c b/gdb/source.c
index d01dff4..32f2178 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1409,12 +1409,14 @@ line_info (char *arg, int from_tty)
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
@@ -1428,11 +1430,15 @@ line_info (char *arg, int from_tty)
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
@@ -1498,7 +1504,7 @@ line_info (char *arg, int from_tty)
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */
diff --git a/gdb/stack.c b/gdb/stack.c
index 003725a..b69547b 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2330,20 +2330,25 @@ func_command (char *arg, int from_tty)
int i;
int level = 1;
struct function_bounds *func_bounds = NULL;
+ struct cleanup *cleanups;
if (arg != NULL)
return;
frame = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
+ cleanups = make_cleanup (xfree, sals.sals);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
+ make_cleanup (xfree, func_bounds);
for (i = 0; (i < sals.nelts && !found); i++)
{
- if (sals.sals[i].pc == 0
- || find_pc_partial_function (sals.sals[i].pc, NULL,
- &func_bounds[i].low,
- &func_bounds[i].high) == 0)
+ if (sals.sals[i].pspace != current_program_space)
+ func_bounds[i].low = func_bounds[i].high = 0;
+ else if (sals.sals[i].pc == 0
+ || find_pc_partial_function (sals.sals[i].pc, NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
{
func_bounds[i].low = func_bounds[i].high = 0;
}
@@ -2362,8 +2367,7 @@ func_command (char *arg, int from_tty)
}
while (!found && level == 0);
- if (func_bounds)
- xfree (func_bounds);
+ do_cleanups (cleanups);
if (!found)
printf_filtered (_("'%s' not within current stack frame.\n"), arg);
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 624df76..d45a226 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -152,22 +152,24 @@ struct quick_symbol_functions
/* Forget all cached full file names for OBJFILE. */
void (*forget_cached_source_info) (struct objfile *objfile);
- /* Look up the symbol table, in OBJFILE, of a source file named
- NAME. If there is no '/' in the name, a match after a '/' in the
- symbol table's file name will also work. FULL_PATH is the
- absolute file name, and REAL_PATH is the same, run through
- gdb_realpath.
-
- If no such symbol table can be found, returns 0.
-
- Otherwise, sets *RESULT to the symbol table and returns 1. This
- might return 1 and set *RESULT to NULL if the requested file is
- an include file that does not have a symtab of its own. */
- int (*lookup_symtab) (struct objfile *objfile,
- const char *name,
- const char *full_path,
- const char *real_path,
- struct symtab **result);
+ /* Expand and iterate over each "partial" symbol table in OBJFILE
+ where the source file is named NAME.
+
+ If there is no '/' in the name, a match after a '/' in the symbol
+ table's file name will also work. FULL_PATH is the absolute file
+ name, and REAL_PATH is the same, run through gdb_realpath.
+
+ If a match is found, the "partial" symbol table is expanded.
+ Then, this calls iterate_over_some_symtabs (or equivalent) over
+ all newly-created symbol tables, passing CALLBACK and DATA to it.
+ The result of this call is returned. */
+ int (*map_symtabs_matching_filename) (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data);
/* Check to see if the symbol is defined in a "partial" symbol table
of OBJFILE. KIND should be either GLOBAL_BLOCK or STATIC_BLOCK,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 9447bd9..a042e2c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -81,7 +81,7 @@ static void sources_info (char *, int);
static void output_source_filename (const char *, int *);
-static int find_line_common (struct linetable *, int, int *);
+static int find_line_common (struct linetable *, int, int *, int);
static struct symbol *lookup_symbol_aux (const char *name,
const struct block *block,
@@ -142,43 +142,36 @@ multiple_symbols_select_mode (void)
const struct block *block_found;
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
+/* Check for a symtab of a specific name by searching some symtabs.
+ This is a helper function for callbacks of iterate_over_symtabs.
-struct symtab *
-lookup_symtab (const char *name)
+ The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA
+ are identical to the `map_symtabs_matching_filename' method of
+ quick_symbol_functions.
+
+ FIRST and AFTER_LAST indicate the range of symtabs to search.
+ AFTER_LAST is one past the last symtab to search; NULL means to
+ search until the end of the list. */
+
+int
+iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last)
{
- int found;
struct symtab *s = NULL;
- struct objfile *objfile;
- char *real_path = NULL;
- char *full_path = NULL;
- struct cleanup *cleanup;
- cleanup = make_cleanup (null_cleanup, NULL);
-
- /* Here we are interested in canonicalizing an absolute path, not
- absolutizing a relative path. */
- if (IS_ABSOLUTE_PATH (name))
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- full_path = xfullpath (name);
- make_cleanup (xfree, full_path);
- real_path = gdb_realpath (name);
- make_cleanup (xfree, real_path);
- }
-
-got_symtab:
-
- /* First, search for an exact match. */
-
- ALL_SYMTABS (objfile, s)
- {
- if (FILENAME_CMP (name, s->filename) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
/* If the user gave us an absolute path, try to find the file in
this symtab and use its absolute path. */
@@ -189,8 +182,8 @@ got_symtab:
if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
{
- do_cleanups (cleanup);
- return s;
+ if (callback (s, data))
+ return 1;
}
}
@@ -204,62 +197,114 @@ got_symtab:
make_cleanup (xfree, rp);
if (FILENAME_CMP (real_path, rp) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
- }
+ }
/* Now, search for a matching tail (only if name doesn't have any dirs). */
if (lbasename (name) == name)
- ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- do_cleanups (cleanup);
- return s;
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
+ return 0;
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work.
+
+ Calls CALLBACK with each symtab that is found and with the supplied
+ DATA. If CALLBACK returns true, the search stops. */
+
+void
+iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data)
+{
+ struct symtab *s = NULL;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ if (iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, NULL))
+ {
+ do_cleanups (cleanups);
+ return;
+ }
+ }
+
/* Same search rules as above apply here, but now we look thru the
psymtabs. */
- found = 0;
ALL_OBJFILES (objfile)
{
if (objfile->sf
- && objfile->sf->qf->lookup_symtab (objfile, name, full_path, real_path,
- &s))
+ && objfile->sf->qf->map_symtabs_matching_filename (objfile,
+ name,
+ full_path,
+ real_path,
+ callback,
+ data))
{
- found = 1;
- break;
+ do_cleanups (cleanups);
+ return;
}
}
- if (s != NULL)
- {
- do_cleanups (cleanup);
- return s;
- }
- if (!found)
- {
- do_cleanups (cleanup);
- return NULL;
- }
+ do_cleanups (cleanups);
+}
+
+/* The callback function used by lookup_symtab. */
- /* At this point, we have located the psymtab for this file, but
- the conversion to a symtab has failed. This usually happens
- when we are looking up an include file. In this case,
- PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
- been created. So, we need to run through the symtabs again in
- order to find the file.
- XXX - This is a crock, and should be fixed inside of the
- symbol parsing routines. */
- goto got_symtab;
+static int
+lookup_symtab_callback (struct symtab *symtab, void *data)
+{
+ struct symtab **result_ptr = data;
+
+ *result_ptr = symtab;
+ return 1;
+}
+
+/* A wrapper for iterate_over_symtabs that returns the first matching
+ symtab, or NULL. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *result = NULL;
+
+ iterate_over_symtabs (name, lookup_symtab_callback, &result);
+ return result;
}
+
\f
/* Mangle a GDB method stub type. This actually reassembles the pieces of the
full method name, which consist of the class name (from T), the unadorned
@@ -994,33 +1039,16 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
return sym;
}
-/* Find the definition for a specified symbol name NAME
- in domain DOMAIN, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-/* This function has a bunch of loops in it and it would seem to be
- attractive to put in some QUIT's (though I'm not really sure
- whether it can run long enough to be really important). But there
- are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
- that there is C++ code below which can error(), but that probably
- doesn't affect these calls since they are looking for a known
- variable and thus can probably assume it will never hit the C++
- code). */
+/* Compute the demangled form of NAME as used by the various symbol
+ lookup functions. The result is stored in *RESULT_NAME. Returns a
+ cleanup which can be used to clean up the result. */
-struct symbol *
-lookup_symbol_in_language (const char *name, const struct block *block,
- const domain_enum domain, enum language lang,
- int *is_a_field_of_this)
+struct cleanup *
+demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
- struct symbol *returnval;
struct cleanup *cleanup = make_cleanup (null_cleanup, 0);
modified_name = name;
@@ -1067,6 +1095,38 @@ lookup_symbol_in_language (const char *name, const struct block *block,
}
}
+ *result_name = modified_name;
+ return cleanup;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
+
+struct symbol *
+lookup_symbol_in_language (const char *name, const struct block *block,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ const char *modified_name;
+ struct symbol *returnval;
+ struct cleanup *cleanup = demangle_for_lookup (name, lang, &modified_name);
+
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
@@ -1759,6 +1819,44 @@ lookup_block_symbol (const struct block *block, const char *name,
}
}
+/* Iterate over the symbols named NAME, matching DOMAIN, starting with
+ BLOCK.
+
+ For each symbol that matches, CALLBACK is called. The symbol and
+ DATA are passed to the callback.
+
+ If CALLBACK returns zero, the iteration ends. Otherwise, the
+ search continues. This function iterates upward through blocks.
+ When the outermost block has been finished, the function
+ returns. */
+
+void
+iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+ SYMBOL_DOMAIN (sym), domain))
+ {
+ if (!callback (sym, data))
+ return;
+ }
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+}
+
/* Find the symtab associated with PC and SECTION. Look through the
psymtabs and read in another symtab if necessary. */
@@ -2184,7 +2282,7 @@ find_line_symtab (struct symtab *symtab, int line,
/* First try looking it up in the given symtab. */
best_linetable = LINETABLE (symtab);
best_symtab = symtab;
- best_index = find_line_common (best_linetable, line, &exact);
+ best_index = find_line_common (best_linetable, line, &exact, 0);
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
@@ -2229,7 +2327,7 @@ find_line_symtab (struct symtab *symtab, int line,
&& FILENAME_CMP (symtab->fullname, s->fullname) != 0)
continue;
l = LINETABLE (s);
- ind = find_line_common (l, line, &exact);
+ ind = find_line_common (l, line, &exact, 0);
if (ind >= 0)
{
if (exact)
@@ -2260,6 +2358,86 @@ done:
return best_symtab;
}
+
+/* qsort comparison function for use by find_pcs_for_symtab_line. */
+
+static int
+compare_core_addrs (const void *a, const void *b)
+{
+ const CORE_ADDR *ca = a;
+ const CORE_ADDR *cb = b;
+
+ return (int) (ca - cb);
+}
+
+/* Given SYMTAB, return one PC per function in the symtab that exactly
+ matches LINE. Returns NULL if none matched. */
+
+VEC (CORE_ADDR) *
+find_pcs_for_symtab_line (struct symtab *symtab, int line)
+{
+ VEC (CORE_ADDR) *result = NULL;
+ int start = 0, ix;
+ struct symbol *previous_function = NULL;
+
+ /* First, collect all the PCs that are at this line. */
+ while (1)
+ {
+ int was_exact;
+ int idx;
+
+ idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+ if (idx < 0)
+ break;
+
+ if (!was_exact)
+ {
+ if (VEC_empty (CORE_ADDR, result))
+ {
+ /* We only found an inexact match. So, redo the search
+ for the found line. */
+ line = LINETABLE (symtab)->item[idx].line;
+ start = 0;
+ continue;
+ }
+ break;
+ }
+
+ VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+ start = idx + 1;
+ }
+
+ if (VEC_empty (CORE_ADDR, result))
+ return result;
+
+ qsort (VEC_address (CORE_ADDR, result), VEC_length (CORE_ADDR, result),
+ sizeof (CORE_ADDR), compare_core_addrs);
+
+ /* Remove all duplicate entries from the result. That is, each
+ function should only appear a single time. */
+ for (ix = 0; ix < VEC_length (CORE_ADDR, result); )
+ {
+ struct symbol *sym;
+ struct block *block;
+
+ block = block_for_pc (VEC_index (CORE_ADDR, result, ix));
+ sym = block ? block_containing_function (block) : NULL;
+
+ if (sym == NULL || sym == previous_function)
+ VEC_ordered_remove (CORE_ADDR, result, ix);
+ else
+ {
+ previous_function = sym;
+ ++ix;
+ }
+ }
+
+ if (VEC_length (CORE_ADDR, result) == 0)
+ VEC_free (CORE_ADDR, result);
+
+ return result;
+}
+
\f
/* Set the PC value for a given source file and line number and return true.
Returns zero for invalid line number (and sets the PC to 0).
@@ -2328,12 +2506,13 @@ find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr,
/* Given a line table and a line number, return the index into the line
table for the pc of the nearest line whose number is >= the specified one.
Return -1 if none is found. The value is >= 0 if it is an index.
+ START is the index at which to start searching the line table.
Set *EXACT_MATCH nonzero if the value returned is an exact match. */
static int
find_line_common (struct linetable *l, int lineno,
- int *exact_match)
+ int *exact_match, int start)
{
int i;
int len;
@@ -2353,7 +2532,7 @@ find_line_common (struct linetable *l, int lineno,
return -1;
len = l->nitems;
- for (i = 0; i < len; i++)
+ for (i = start; i < len; i++)
{
struct linetable_entry *item = &(l->item[i]);
@@ -4486,8 +4665,7 @@ decode_line_spec (char *string, int funfirstline)
cursal = get_current_source_symtab_and_line ();
sals = decode_line_1 (&string, funfirstline,
- cursal.symtab, cursal.line,
- NULL);
+ cursal.symtab, cursal.line);
if (*string)
error (_("Junk at end of line specification: %s"), string);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 90a6fe4..03f9a7a 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -22,6 +22,8 @@
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
+#include "vec.h"
+
/* Opaque declarations. */
struct ui_file;
struct frame_info;
@@ -1057,6 +1059,12 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern void iterate_over_minimal_symbols (struct objfile *objf,
+ const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data);
+
extern int in_gnu_ifunc_stub (CORE_ADDR pc);
/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
@@ -1307,4 +1315,30 @@ void fixup_section (struct general_symbol_info *ginfo,
struct objfile *lookup_objfile_from_block (const struct block *block);
+int iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last);
+
+void iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data);
+
+DEF_VEC_I (CORE_ADDR);
+
+VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line);
+
+void iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data);
+
+struct cleanup *demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name);
+
#endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 8b22324..d3c9cfc 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
- gdb.java gdb.mi gdb.modula2 gdb.multi \
+ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
$(SUBDIRS)
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 82206b3..fb70b3d 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4166,6 +4166,7 @@ do
"gdb.hp/gdb.aCC/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.aCC/Makefile" ;;
"gdb.hp/gdb.compat/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.compat/Makefile" ;;
"gdb.hp/gdb.defects/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.defects/Makefile" ;;
+ "gdb.linespec/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.linespec/Makefile" ;;
"gdb.mi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
"gdb.modula2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.multi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 8631442..121fd37 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -95,7 +95,7 @@ AC_OUTPUT([Makefile \
gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
- gdb.hp/gdb.defects/Makefile \
+ gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \
gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \
diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp
index 92fcc69..c5885ba 100644
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -540,8 +540,9 @@ gdb_test_multiple "catch exec" "$name" {
# Verify that GDB responds gracefully when asked to set a breakpoint
# on a nonexistent source line.
#
+gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in file .*" \
+ "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/list.exp b/gdb/testsuite/gdb.base/list.exp
index 5b9fe15..d4935ee 100644
--- a/gdb/testsuite/gdb.base/list.exp
+++ b/gdb/testsuite/gdb.base/list.exp
@@ -489,7 +489,7 @@ proc test_list_filename_and_function {} {
gdb_test "list foobar.c:main" "No source file named foobar.c.|Location not found" "list filename:function; nonexistant file"
- gdb_test "list list0.h:foobar" "Function \"foobar\" not defined.|Location not found" "list filename:function; nonexistant function"
+ gdb_test "list list0.h:foobar" "Function \"foobar\" not defined in \"list0.h\"." "list filename:function; nonexistant function"
}
diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp
index 1a9072d..bb0b914 100644
--- a/gdb/testsuite/gdb.base/sepdebug.exp
+++ b/gdb/testsuite/gdb.base/sepdebug.exp
@@ -337,7 +337,8 @@ gdb_test_multiple "catch exec" $name {
# on a nonexistent source line.
#
-gdb_test "break 999" "No line 999 in file .*" \
+gdb_test_no_output "set breakpoint pending off"
+gdb_test "break 999" "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index aa723c6..d402ebb 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -46,11 +46,6 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $binfile_lib
-if ![runto_main] then {
- fail "Can't run to main"
- return 0
-}
-
# Set a breakpoint in the binary.
gdb_test "br foo2" \
"Breakpoint.*file.*${testfile}\\.c.*" \
@@ -58,6 +53,11 @@ gdb_test "br foo2" \
delete_breakpoints
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
# Break in the library.
gdb_test "br foo" \
"Breakpoint.*file.*${libname}\\.c.*" \
@@ -67,9 +67,9 @@ gdb_test "continue" \
"Continuing.*" \
"continue"
-# This symbol is now looked up in the ELF library.
+# This symbol is now looked up in the ELF library and the binary.
gdb_test "br foo2" \
- "Breakpoint.*file.*${libname}\\.c.*" \
+ "Breakpoint.*: foo2. .2 locations..*" \
"foo2 in mdlib"
gdb_exit
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 6a99175..0438424 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -50,13 +50,13 @@ if ![runto_main] then {
# and a condition.
gdb_test "break 'Derived::Derived(int)'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
"set-breakpoint at ctor"
gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
gdb_test "break 'Derived::~Derived()'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
"set-breakpoint at dtor"
gdb_test "continue" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index d670b56..05b378c 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -62,7 +62,7 @@ set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
# Set a breakpoint with multiple locations.
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set breakpoint"
gdb_run_cmd
@@ -128,7 +128,7 @@ if { ![runto_main] } {
}
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 80c080b..933d690 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -52,7 +52,7 @@ set bp_location [gdb_get_line_number "set breakpoint here"]
# and a condition.
gdb_test "break $srcfile:$bp_location if i==1" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"initial condition: set breakpoint"
gdb_run_cmd
@@ -80,7 +80,7 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"separate condition: set breakpoint"
gdb_test_no_output "condition 1 i==1" \
@@ -177,7 +177,7 @@ if { ![runto_main] } {
}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/method2.exp b/gdb/testsuite/gdb.cp/method2.exp
index 2fa4169..29a387d 100644
--- a/gdb/testsuite/gdb.cp/method2.exp
+++ b/gdb/testsuite/gdb.cp/method2.exp
@@ -51,7 +51,7 @@ proc test_break { lang } {
"setting language $lang"
gdb_test_multiple "break A::method" "breaking in method ($lang)" {
- -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. A::method\\(A\\*\\) at .*\[\r\n\]*.3. A::method\\(int\\) at .*\[\r\n\]*\[\r\n\]*.4. A::method\\(\\) at .*\[\r\n\]*> $" {
+ -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. .*:A::method\\(A\\*\\)\[\r\n\]*.3. .*:A::method\\(int\\)\[\r\n\]*.4. .*:A::method\\(\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"breaking in method ($lang)"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index f5d4051..f5b41ab 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -130,18 +130,18 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} {
set menu_overload1arg "\\\[0\\\] cancel\r\n"
append menu_overload1arg "\\\[1\\\] all\r\n"
-append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n"
-append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n"
-append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n"
-append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n"
-append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n"
-append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n"
-append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n"
-append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n"
-append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n"
-append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n"
-append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n"
-append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n"
+append menu_overload1arg "\\\[2\\\] .*$srcfile:foo::overload1arg\\(double\\)\r\n"
+append menu_overload1arg "\\\[3\\\] .*$srcfile:foo::overload1arg\\(float\\)\r\n"
+append menu_overload1arg "\\\[4\\\] .*$srcfile:foo::overload1arg\\((unsigned long|long unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[5\\\] .*$srcfile:foo::overload1arg\\(long( int)?\\)\r\n"
+append menu_overload1arg "\\\[6\\\] .*$srcfile:foo::overload1arg\\((unsigned int|unsigned)\\)\r\n"
+append menu_overload1arg "\\\[7\\\] .*$srcfile:foo::overload1arg\\(int\\)\r\n"
+append menu_overload1arg "\\\[8\\\] .*$srcfile:foo::overload1arg\\((unsigned short|short unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[9\\\] .*$srcfile:foo::overload1arg\\(short( int)?\\)\r\n"
+append menu_overload1arg "\\\[10\\\] .*$srcfile:foo::overload1arg\\(unsigned char\\)\r\n"
+append menu_overload1arg "\\\[11\\\] .*$srcfile:foo::overload1arg\\(signed char\\)\r\n"
+append menu_overload1arg "\\\[12\\\] .*$srcfile:foo::overload1arg\\(char\\)\r\n"
+append menu_overload1arg "\\\[13\\\] .*$srcfile:foo::overload1arg\\((void|)\\)\r\n"
append menu_overload1arg "> $"
# Set multiple-symbols to "ask", to allow us to test the use
@@ -279,7 +279,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $decimal at $hex: file.*$srcfile, line 121.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 120.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 119.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 118.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 117.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 116.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 115.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 114.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 113.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 112.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 111.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 110.\r\nwarning: Multiple breakpoints were set.\r\nUse the .delete. command to delete unwanted breakpoints.\r\n$gdb_prompt $" {
+ -re "Breakpoint $decimal at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -306,18 +306,19 @@ gdb_expect {
gdb_test "info break" \
"Num Type\[\t \]+Disp Enb Address\[\t \]+What.*
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
+\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+<MULTIPLE>\[\t \]*\r
+\[0-9\]+.1\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
+\[0-9\]+.2\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
+\[0-9\]+.3\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
+\[0-9\]+.4\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
+\[0-9\]+.5\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
+\[0-9\]+.6\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
+\[0-9\]+.7\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
+\[0-9\]+.8\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
+\[0-9\]+.9\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
+\[0-9\]+.10\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
+\[0-9\]+.11\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
+\[0-9\]+.12\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
"breakpoint info (after setting on all)"
@@ -333,10 +334,10 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
send_gdb "continue\n"
gdb_expect {
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
pass "continue to bp overloaded : ${argtype}"
}
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
if $might_kfail {
kfail "gdb/1025" "continue to bp overloaded : ${argtype}"
} else {
@@ -352,17 +353,17 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
}
}
-continue_to_bp_overloaded 0 25 "(void|)" ""
-continue_to_bp_overloaded 1 24 "char" "arg=2 \\'\\\\002\\'"
-continue_to_bp_overloaded 1 23 "signed char" "arg=3 \\'\\\\003\\'"
-continue_to_bp_overloaded 1 22 "unsigned char" "arg=4 \\'\\\\004\\'"
-continue_to_bp_overloaded 1 21 "short" "arg=5"
-continue_to_bp_overloaded 1 20 "unsigned short" "arg=6"
-continue_to_bp_overloaded 0 19 "int" "arg=7"
-continue_to_bp_overloaded 0 18 "(unsigned|unsigned int)" "arg=8"
-continue_to_bp_overloaded 0 17 "long" "arg=9"
-continue_to_bp_overloaded 0 16 "unsigned long" "arg=10"
-continue_to_bp_overloaded 0 15 "float" "arg=100"
+continue_to_bp_overloaded 0 14 "(void|)" ""
+continue_to_bp_overloaded 1 14 "char" "arg=2 \\'\\\\002\\'"
+continue_to_bp_overloaded 1 14 "signed char" "arg=3 \\'\\\\003\\'"
+continue_to_bp_overloaded 1 14 "unsigned char" "arg=4 \\'\\\\004\\'"
+continue_to_bp_overloaded 1 14 "short" "arg=5"
+continue_to_bp_overloaded 1 14 "unsigned short" "arg=6"
+continue_to_bp_overloaded 0 14 "int" "arg=7"
+continue_to_bp_overloaded 0 14 "(unsigned|unsigned int)" "arg=8"
+continue_to_bp_overloaded 0 14 "long" "arg=9"
+continue_to_bp_overloaded 0 14 "unsigned long" "arg=10"
+continue_to_bp_overloaded 0 14 "float" "arg=100"
continue_to_bp_overloaded 1 14 "double" "arg=200"
# Test breaking on an overloaded function when multiple-symbols
@@ -375,7 +376,7 @@ gdb_test "break foo::foofunc" \
# is set to "all"
gdb_test_no_output "set multiple-symbols all"
gdb_test "break foo::foofunc" \
- "Breakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nBreakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nwarning: Multiple breakpoints were set\\.\r\nUse the \"delete\" command to delete unwanted breakpoints\\."
+ "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*"
# That's all, folks.
diff --git a/gdb/testsuite/gdb.cp/re-set-overloaded.exp b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
index 2052552..bd5f3ba 100644
--- a/gdb/testsuite/gdb.cp/re-set-overloaded.exp
+++ b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
@@ -46,7 +46,6 @@ gdb_test_no_output {set variable $brk = $bpnum}
# runto or runto_main would call delete_breakpoints.
gdb_breakpoint "main"
gdb_run_cmd
-setup_kfail breakpoints/11657 *-*-*
gdb_test "" ".*" "start"
set test "breakpoint resolved"
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 6612b4a..16ce8f7 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -109,7 +109,7 @@ proc test_template_breakpoints {} {
global hp_aCC_compiler
gdb_test_multiple "break T5<int>::T5" "constructor breakpoint" {
- -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5<int>::T5\\(int\\) at .*\[\r\n\]*.3. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*\[\r\n\]*> $" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\)\[\r\n\]*.3.*templates.cc:T5<int>::T5\\(int\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"constructor breakpoint (obsolete format!)"
@@ -153,7 +153,7 @@ proc test_template_breakpoints {} {
set bp_location [gdb_get_line_number \
"set breakpoint on a line with no real code"]
gdb_test "break ${testfile}.cc:${bp_location}" \
- "Breakpoint.*at.* file .*${testfile}.cc, line.*(2 locations).*" \
+ "Breakpoint.*at.*: .*${testfile}.cc:${bp_location}.*(2 locations).*" \
"breakpoint on a line with no real code"
delete_breakpoints
}
diff --git a/gdb/testsuite/gdb.linespec/Makefile.in b/gdb/testsuite/gdb.linespec/Makefile.in
new file mode 100644
index 0000000..2658a24
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/Makefile.in
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = lspec
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
new file mode 100644
index 0000000..882ccc9
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+
+
+
+
+
+int m(int x)
+{
+ return x + 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(int x)
+{
+ return x + 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
new file mode 100644
index 0000000..43917f8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+static int dupname(int y)
+{
+ label: return y;
+}
+
+int n(int y)
+{
+ return dupname(y) - 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(double x)
+{
+ return (int) x - 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
new file mode 100644
index 0000000..122a468
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -0,0 +1,106 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of ambiguous linespecs.
+
+set testfile linespec
+
+set exefile lspec
+set binfile ${objdir}/${subdir}/${exefile}
+
+set baseone base/one/thefile.cc
+set basetwo base/two/thefile.cc
+
+set hex {0x[0-9a-fA-F]+}
+
+if {[skip_cplus_tests]} {
+ unsupported linespec.exp
+ return
+}
+
+if {[prepare_for_testing ${testfile}.exp $exefile \
+ [list lspec.cc $baseone $basetwo] \
+ {debug nowarnings}]} {
+ return -1
+}
+
+gdb_test_no_output "set multiple-symbols all" \
+ "set multiple-symbols to all for linespec tests"
+
+set l1 [gdb_get_line_number "thefile breakpoint" $baseone]
+set l2 [gdb_get_line_number "thefile breakpoint" $basetwo]
+
+if {$l1 != $l2} {
+ error "somebody incompatibly modified the source files needed by linespec.exp"
+}
+
+gdb_test "break thefile.cc:$l1" \
+ "Breakpoint 1 at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
+ "multi-location break using file:line"
+
+# We'd like this to work, but it currently does not.
+# gdb_test "break one/thefile.cc:$l1"
+
+gdb_test "break dupname" \
+ "Breakpoint 2 at $hex: dupname. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name"
+
+gdb_test "break dupname:label" \
+ "Breakpoint 3 at $hex: dupname:label. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name and label"
+
+gdb_test_no_output "set breakpoint pending off" \
+ "disable pending breakpoints for linespec tests"
+
+# This is PR breakpoints/12856.
+gdb_test "break lspec.cc:nosuchfunction" \
+ "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
+ "set breakpoint on non-existent function"
+
+gdb_test "break NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
+ "set breakpoint at all instances of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at lspec.cc instance of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload(double)" \
+ "Function \"NameSpace::overload\\(double\\)\" not defined in \"lspec.cc\"." \
+ "set breakpoint at non-existent lspec.cc instance of NameSpace::overload"
+
+gdb_test "break NameSpace::overload()" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at specific instance of NameSpace::overload"
+
+#
+# Multi-inferior tests.
+#
+
+gdb_test "add-inferior" "Added inferior 2" \
+ "add inferior for linespec tests"
+
+gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch to inferior 2 for linespec tests"
+
+# Note that in particular this should not cause errors when re-setting
+# breakpoints.
+gdb_test "file $binfile" \
+ "Reading symbols from .*done." \
+ "set the new inferior file for linespec tests"
+
+gdb_test "break main" \
+ "Breakpoint \[0-9\]+ at $hex: main. .2 locations." \
+ "set breakpoint at main in both inferiors"
diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc
new file mode 100644
index 0000000..42e382f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.cc
@@ -0,0 +1,13 @@
+#include "lspec.h"
+
+static int dupname (int x) { label: return x; }
+
+int NameSpace::overload()
+{
+ return 23;
+}
+
+int main()
+{
+ return dupname(0) + m(0) + n(0);
+}
diff --git a/gdb/testsuite/gdb.linespec/lspec.h b/gdb/testsuite/gdb.linespec/lspec.h
new file mode 100644
index 0000000..e4bfc00
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.h
@@ -0,0 +1,9 @@
+extern int m(int x);
+extern int n(int y);
+
+namespace NameSpace {
+ int overload ();
+ int overload (int);
+ int overload (double);
+};
+
diff --git a/gdb/testsuite/gdb.objc/objcdecode.exp b/gdb/testsuite/gdb.objc/objcdecode.exp
index 720bfd8..098dd57 100644
--- a/gdb/testsuite/gdb.objc/objcdecode.exp
+++ b/gdb/testsuite/gdb.objc/objcdecode.exp
@@ -62,7 +62,7 @@ gdb_test_multiple "break multipleDef" $name \
send_gdb "3\n"
exp_continue
}
- -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*\r\n$gdb_prompt $" { pass $name }
+ -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: multipleDef.\r\n$gdb_prompt $" { pass $name }
-re ".*$gdb_prompt $" { kfail "gdb/1236" $name }
}
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 679cc32..89a2e24 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -74,6 +74,7 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline2" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
+gdb_test_no_output "set breakpoint pending off"
gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
@@ -81,7 +82,6 @@ gdb_test "info trace" "No tracepoints.*" \
# 1.3 trace line in invalid source file
gdb_delete_tracepoints
-gdb_test_no_output "set breakpoint pending off"
gdb_test "trace NoSuChFiLe.c:1" "No source file named NoSuChFiLe.c." \
"1.3a: trace invalid source file"
gdb_test "info trace" "No tracepoints.*" \
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 23f3071..16f311f 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2388,7 +2388,7 @@ scope_info (char *args, int from_tty)
error (_("requires an argument (function, "
"line or *addr) to define a scope"));
- sals = decode_line_1 (&args, 1, NULL, 0, NULL);
+ sals = decode_line_1 (&args, 1, NULL, 0);
if (sals.nelts == 0)
return; /* Presumably decode_line_1 has already warned. */
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 4c8658d..9b936e1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -455,29 +455,34 @@ tui_update_breakpoint_info (struct tui_win_info *win,
bp != (struct breakpoint *) NULL;
bp = bp->next)
{
+ struct bp_location *loc;
+
gdb_assert (line->line_or_addr.loa == LOA_LINE
|| line->line_or_addr.loa == LOA_ADDRESS);
- if ((win == TUI_SRC_WIN
- && bp->source_file
- && (filename_cmp (src->filename, bp->source_file) == 0)
- && line->line_or_addr.loa == LOA_LINE
- && bp->line_number == line->line_or_addr.u.line_no)
- || (win == TUI_DISASM_WIN
- && line->line_or_addr.loa == LOA_ADDRESS
- && bp->loc != NULL
- && bp->loc->address == line->line_or_addr.u.addr))
- {
- if (bp->enable_state == bp_disabled)
- mode |= TUI_BP_DISABLED;
- else
- mode |= TUI_BP_ENABLED;
- if (bp->hit_count)
- mode |= TUI_BP_HIT;
- if (bp->loc->cond)
- mode |= TUI_BP_CONDITIONAL;
- if (bp->type == bp_hardware_breakpoint)
- mode |= TUI_BP_HARDWARE;
- }
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && loc->source_file
+ && (filename_cmp (src->filename, loc->source_file) == 0)
+ && line->line_or_addr.loa == LOA_LINE
+ && loc->line_number == line->line_or_addr.u.line_no)
+ || (win == TUI_DISASM_WIN
+ && line->line_or_addr.loa == LOA_ADDRESS
+ && loc->address == line->line_or_addr.u.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->loc->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
}
if (line->has_break != mode)
{
diff --git a/gdb/utils.c b/gdb/utils.c
index 5c03e71..ee96562 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3684,6 +3684,17 @@ compare_positive_ints (const void *ap, const void *bp)
return * (int *) ap - * (int *) bp;
}
+/* String compare function for qsort. */
+
+int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+
+ return strcmp (*s1, *s2);
+}
+
#define AMBIGUOUS_MESS1 ".\nMatching formats:"
#define AMBIGUOUS_MESS2 \
".\nUse \"set gnutarget format-name\" to specify the format."
--
1.7.6.4
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-10-28 17:34 RFA: implement ambiguous linespec proposal Tom Tromey
@ 2011-10-28 20:52 ` Matt Rice
2011-11-01 20:38 ` Tom Tromey
2011-10-28 22:41 ` Jan Kratochvil
1 sibling, 1 reply; 42+ messages in thread
From: Matt Rice @ 2011-10-28 20:52 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Fri, Oct 28, 2011 at 9:28 AM, Tom Tromey <tromey@redhat.com> wrote:
> I'd appreciate comments on this patch.
In the following snippet, the initial comment doesn't mention
destroy_linespec_result,
and some of the field comments mention that the caller is responsible
for freeing.
destroy_linespec_result seems to fulfill this obligation,
I imagine that the comments just predate destroy_linespec_result, or
there is an OR situation e.g. if the caller wants to save some fields
they are responsible. Anyhow it'd be nice to clarify that in the
comments.
thanks
> /* An instance of this may be filled in by decode_line_1. The caller
> must call init_linespec_result to initialize it. */
>
> @@ -30,22 +49,85 @@ struct linespec_result
> display mechanism would do the wrong thing. */
> int special_display;
>
> - /* If non-NULL, an array of canonical names for returned
> - symtab_and_line objects. The array has as many elements as the
> - `nelts' field in the symtabs_and_line returned by decode_line_1.
> - An element in the array may be NULL. The array and each non-NULL
> - element in it are allocated with xmalloc and must be freed by the
> - caller. */
> - char **canonical;
> + /* If non-zero, the linespec result should be considered to be a
> + "pre-expanded" multi-location linespec. A pre-expanded linespec
> + holds all matching locations in a single linespec_sals
> + object. */
> + int pre_expanded;
> +
> + /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
> + by the user. This is allocated with xmalloc and the caller is
> + responsible for freeing it. */
> + char *addr_string;
> +
> + /* The sals. The vector should be freed by the caller. */
> + VEC (linespec_sals) *sals;
> };
>
> /* Initialize a linespec_result. */
>
> extern void init_linespec_result (struct linespec_result *);
>
> +/* Destroy a linespec_result. */
> +
> +extern void destroy_linespec_result (struct linespec_result *);
> +
> +/* Return a cleanup that destroys a linespec_result. */
> +
> +extern struct cleanup *
> + make_cleanup_destroy_linespec_result (struct linespec_result *);
> +
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-10-28 17:34 RFA: implement ambiguous linespec proposal Tom Tromey
2011-10-28 20:52 ` Matt Rice
@ 2011-10-28 22:41 ` Jan Kratochvil
2011-11-01 20:58 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-10-28 22:41 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Fri, 28 Oct 2011 18:28:09 +0200, Tom Tromey wrote:
> I built and regression tested this on x86-64 F15.
It has no regressions on Fedora 16 x86_64 but:
On Fedora 16 x86_64 with -m32 and on Fedora 16 i386:
-PASS: gdb.base/step-line.exp: break f1
+FAIL: gdb.base/step-line.exp: break f1
-PASS: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
+FAIL: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
-PASS: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
+FAIL: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
Just on Fedora 16 x86_64 with -m32:
-PASS: gdb.threads/thread_check.exp: breakpoint at tf
+FAIL: gdb.threads/thread_check.exp: breakpoint at tf
Not yet read it all, just the testsuite check. Great so many issues fixed.
Thanks,
Jan
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-10-28 20:52 ` Matt Rice
@ 2011-11-01 20:38 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-01 20:38 UTC (permalink / raw)
To: Matt Rice; +Cc: gdb-patches
>>>>> "Matt" == Matt Rice <ratmice@gmail.com> writes:
Tom> I'd appreciate comments on this patch.
Matt> In the following snippet, the initial comment doesn't mention
Matt> destroy_linespec_result, and some of the field comments mention
Matt> that the caller is responsible for freeing.
Matt> destroy_linespec_result seems to fulfill this obligation,
Matt> I imagine that the comments just predate destroy_linespec_result, or
Matt> there is an OR situation e.g. if the caller wants to save some fields
Matt> they are responsible. Anyhow it'd be nice to clarify that in the
Matt> comments.
Yeah, that's what happened.
Thanks for noticing this; I cleaned up the comments on my local branch.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-10-28 22:41 ` Jan Kratochvil
@ 2011-11-01 20:58 ` Tom Tromey
2011-11-03 20:49 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-01 20:58 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> -PASS: gdb.base/step-line.exp: break f1
Jan> +FAIL: gdb.base/step-line.exp: break f1
This fails because there is a (data) symbol named 'f1' in libm.
I think 'break' and friends will have to pass in a flag meaning "only
look for text symbols".
Jan> -PASS: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
Jan> +FAIL: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
Jan> -PASS: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
Jan> +FAIL: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
I don't like how this test assumes that gdb will do a namespace search
for a symbol when decoding linespecs. That just seems wrong to me.
But, we've shipped it for a while, so I think we'll have to cope.
I think I will need a new language method to handle this properly.
The test itself is bogus since it makes an assumption about which
overload 'inner::foo' will match. I think it should match all of them,
and in one of them there is no symbol named 'a'.
Jan> Just on Fedora 16 x86_64 with -m32:
Jan> -PASS: gdb.threads/thread_check.exp: breakpoint at tf
Jan> +FAIL: gdb.threads/thread_check.exp: breakpoint at tf
Similar to step-line, 'tf' is a .bss symbol in libc.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-01 20:58 ` Tom Tromey
@ 2011-11-03 20:49 ` Tom Tromey
2011-11-04 7:46 ` Jan Kratochvil
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-03 20:49 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
Jan> -PASS: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
Jan> +FAIL: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
Jan> -PASS: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
Jan> +FAIL: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
Tom> I don't like how this test assumes that gdb will do a namespace search
Tom> for a symbol when decoding linespecs. That just seems wrong to me.
Tom> But, we've shipped it for a while, so I think we'll have to cope.
I am not sure we can make this work sanely. I'm tempted to declare
these tests invalid and remove them.
Consider this program:
namespace N1 {
int m() { return 23; }
};
namespace N2 {
int m() { return 23; }
};
int main()
{
using namespace N1;
using namespace N2;
return 0;
}
I think this is valid (g++ accepts it).
What should gdb do if we are stopped in 'main' and the user types 'break m'?
Doing namespace searches is a problem if they yield an ambiguous result
because either:
1. There is no canonical name that can be put into the breakpoint for
resetting, or
2. The breakpoint would have to also capture the current block for
re-setting, which opens a whole new set of problems.
I understand that the rationale here is for gdb to work like the
compiler does. And, I still think that makes a lot of sense for
expressions. But for linespecs I am not convinced, as I think they are
different in nature: they may be re-parsed in many different contexts
and they may apply across objfiles and program spaces. Also, for C++ at
least, I think "work like the compiler" will have more awful
implications: ADL, template stuff, ... I would rather just require the
user to type what they mean.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-03 20:49 ` Tom Tromey
@ 2011-11-04 7:46 ` Jan Kratochvil
2011-11-08 16:36 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-11-04 7:46 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Thu, 03 Nov 2011 21:48:56 +0100, Tom Tromey wrote:
[...]
> namespace N1 {
> int m() { return 23; }
> };
>
> namespace N2 {
> int m() { return 23; }
> };
>
> int main()
> {
> using namespace N1;
> using namespace N2;
> return 0;
> }
>
> I think this is valid (g++ accepts it).
>
> What should gdb do if we are stopped in 'main' and the user types 'break m'?
>
>
> Doing namespace searches is a problem if they yield an ambiguous result
> because either:
>
> 1. There is no canonical name that can be put into the breakpoint for
> resetting, or
>
> 2. The breakpoint would have to also capture the current block for
> re-setting, which opens a whole new set of problems.
>
>
> I understand that the rationale here is for gdb to work like the
> compiler does.
Compiler says:
.C:13:6: error: call of overloaded ‘m()’ is ambiguous
.C:13:6: note: candidates are:
.C:6:7: note: int N2::m()
.C:2:7: note: int N1::m()
and I think GDB should also say the same output as error.
It is questionable what it should do on re-set if it becomes ambigous. One
can store the available namespaces as strings with the breakpoint (instead of
storing pointer to the block - where the block may disappear).
I understand it is not feasible to throw an error if ambiguity happens later
on a breakpoint re-set, so a multi-location breakpoint is probably OK.
Which brings a question whether the multi-location breakpoint should not be
placed there already when creating the breakpoint (instead of the suggested
error). As GDB already ignores `static' for variables in other files and
already ignores even C++ access specifiers it cannot work exactly like the
compiler anyway.
> I would rather just require the user to type what they mean.
It breaks that GDB should be able to parse what the source says.
Thanks,
Jan
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-04 7:46 ` Jan Kratochvil
@ 2011-11-08 16:36 ` Tom Tromey
2011-11-09 16:05 ` Joel Brobecker
2011-11-09 18:37 ` Tom Tromey
0 siblings, 2 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-08 16:36 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> Compiler says:
Jan> .C:13:6: error: call of overloaded ‘m()’ is ambiguous
Jan> .C:13:6: note: candidates are:
Jan> .C:6:7: note: int N2::m()
Jan> .C:2:7: note: int N1::m()
Jan> and I think GDB should also say the same output as error.
I agree for expressions. I think linespecs are different.
For example, with ADL, a plain name like "function" may be looked up in
the namespaces of the arguments. I don't see how linespec will ever
handle this sanely.
GDB is already inconsistent here, BTW. For example, "break k::m" will
search superclasses of "k", but "break m" will not search superclasses
of the class of *this.
I have been thinking about this, though, and I think there is another
approach that could work.
Jan> One can store the available namespaces as strings with the
Jan> breakpoint (instead of storing pointer to the block - where the
Jan> block may disappear).
Yeah. I would like to store as little context as possible, though. Or,
rather, I would like all the context to appear in the linespec's
canonical form.
The way we could make this work is that we could have decode_line_full
return sets of SALs, where each set is distinguished by its canonical
name. So, in this case, we would return two sets, one "N1::m" and one
"N2::m".
Then, this would create two separate breakpoints -- one per set.
This is more complicated than just rejecting this case, but it would let
us preserve namespace searches.
I think it would also make some Ada cases work more sanely, though I
don't know enough to say with certainty. I'm thinking here about how
ada_lookup_symbol_list returns a list but then the linespec code only
uses the first one (via some call through ada_lookup_encoded_symbol, I
don't remember the details).
My problem with this is that it adds more complexity to the user
interface: some linespecs will create a single breakpoint with multiple
locations, some will create multiple breakpoints once again, depending
on the context.
So, I am still against it, but I will take a stab at it if you think it
is important.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-08 16:36 ` Tom Tromey
@ 2011-11-09 16:05 ` Joel Brobecker
2011-11-09 17:12 ` Tom Tromey
2011-11-09 18:37 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Joel Brobecker @ 2011-11-09 16:05 UTC (permalink / raw)
To: Tom Tromey, Jerome Guitton; +Cc: Jan Kratochvil, gdb-patches
> I think it would also make some Ada cases work more sanely, though I
> don't know enough to say with certainty. I'm thinking here about how
> ada_lookup_symbol_list returns a list but then the linespec code only
> uses the first one (via some call through ada_lookup_encoded_symbol, I
> don't remember the details).
You are missing part of the picture, I think, because some of our code
is not in the FSF tree [1]. We get multiple breakpoints for situations
such as homonyms, or generics (aka templates in C++) instantiations.
In that situation, I think that the FSF GDB only picks the first one,
whereas AdaCore's GDB creates multiple breakpoints.
> My problem with this is that it adds more complexity to the user
> interface: some linespecs will create a single breakpoint with multiple
> locations, some will create multiple breakpoints once again, depending
> on the context.
We have a similar issue: When the user inserts a breakpoint, and there
are multiple possible choices, we have two scnearios:
1. He selects `all' -> In that case, we actually create one breakpoint
with multiple locations;
2. He selects a subset -> In that situation, we create one breakpoint
per location.
I think this can be pretty confusing.
I am copying Jerome Guitton on this message, since he did the work
for that.
--
Joel
[1]: We tried contributing it, but it was too hacky to really be part
of the FSF sources. The main complaint at the time was the fact
that it introduced a canonical form that was specific to Ada. I was
planning on looking at generalizing it to all languages, but never
got around to doing it.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 16:05 ` Joel Brobecker
@ 2011-11-09 17:12 ` Tom Tromey
2011-11-09 17:56 ` Joel Brobecker
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-09 17:12 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Jerome Guitton, Jan Kratochvil, gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Joel> We have a similar issue: When the user inserts a breakpoint, and there
Joel> are multiple possible choices, we have two scnearios:
Joel> 1. He selects `all' -> In that case, we actually create one breakpoint
Joel> with multiple locations;
Joel> 2. He selects a subset -> In that situation, we create one breakpoint
Joel> per location.
Joel> I think this can be pretty confusing.
This happens with the new code too, though it depends on the
'multiple-symbols' setting. For 'all', there is no menu, just a
breakpoint with all the locations.
The code is based around the idea that a linespec has a canonical form.
Re-setting is done based by re-parsing the original linespec (though
there are exceptions to this rule -- linespec is pretty complicated);
but filtering is done based on the canonical form.
The exception to the re-parsing rule is for linespecs where the original
text is context-relative. For example, "break 57" -- it would not make
sense to try to re-parse "57", instead linespec returns a form of
"file.c:57".
So, I misspoke a little upthread. The problem with the searching
namespace using declarations for C++ is that the linespec is
context-relative, but there is no unique non-relative form we can
rewrite. That is, in the example, the rewritten form for re-parsing
would have to be both "N1::m" and "N2::m".
Joel> [1]: We tried contributing it, but it was too hacky to really be part
Joel> of the FSF sources. The main complaint at the time was the fact
Joel> that it introduced a canonical form that was specific to Ada. I was
Joel> planning on looking at generalizing it to all languages, but never
Joel> got around to doing it.
Do you have a URL? This would be a good time to resurrect it.
I would like to take a look... I don't know Ada, though, so I'm going to
guess that I probably won't be able to fix it up.
In terms of the proposed patch, the key question is whether rewriting is
needed for Ada, and if so, whether it can be done uniquely. Or, if
using the simple name is always enough... in this case the solution is
very easy.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 17:12 ` Tom Tromey
@ 2011-11-09 17:56 ` Joel Brobecker
2011-11-09 18:19 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Joel Brobecker @ 2011-11-09 17:56 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jerome Guitton, Jan Kratochvil, gdb-patches
> Joel> [1]: We tried contributing it, but it was too hacky to really be part
> Joel> of the FSF sources. The main complaint at the time was the fact
> Joel> that it introduced a canonical form that was specific to Ada. I was
> Joel> planning on looking at generalizing it to all languages, but never
> Joel> got around to doing it.
>
> Do you have a URL? This would be a good time to resurrect it.
Sure, although I don't know if you really need to re-read the messages
or not. I think you already know quite a bit about it, and I can tell
you the rest...
http://www.sourceware.org/ml/gdb-patches/2008-01/msg00008.html
Another message regarding the subject, this time involving Pascal:
http://www.sourceware.org/ml/gdb-patches/2008-09/msg00379.html
> I would like to take a look... I don't know Ada, though, so I'm going to
> guess that I probably won't be able to fix it up.
And I don't really expect you to. Either I fix it up with you, or
maybe you provide a hook somewhere that I can then implement, etc.
> In terms of the proposed patch, the key question is whether rewriting
> is needed for Ada, and if so, whether it can be done uniquely.
It is needed, and that's what we do at AdaCore. That's the new
canonical form that I was mentioning in the previous messages.
I don't think it is 100% unique, but it's pretty close, and I think
it's the best we can do (we've never heard reports of problems
with that form in the 10+ years we've been using it).
The canonical form for Ada is: FILE:FUNCTION_NAME:LINE_NO. Once
written in that form, the linespec parser should always re-evaluate
it into one single logical breakpoint (with potentially multiple
locations).
The question is, can we use that same form for everyone? I thought
you were going to do unconditional rewriting of the location string,
but now I'm not so sure anymore...
--
Joel
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 17:56 ` Joel Brobecker
@ 2011-11-09 18:19 ` Tom Tromey
2011-11-09 19:00 ` Joel Brobecker
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-09 18:19 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Jerome Guitton, Jan Kratochvil, gdb-patches
Joel> It is needed, and that's what we do at AdaCore. That's the new
Joel> canonical form that I was mentioning in the previous messages.
Joel> I don't think it is 100% unique, but it's pretty close, and I think
Joel> it's the best we can do (we've never heard reports of problems
Joel> with that form in the 10+ years we've been using it).
Joel> The canonical form for Ada is: FILE:FUNCTION_NAME:LINE_NO. Once
Joel> written in that form, the linespec parser should always re-evaluate
Joel> it into one single logical breakpoint (with potentially multiple
Joel> locations).
Oh, ok. I forgot all the discussions we've had on this, maybe since I
was fixated on ada_lookup_symbol_list, or maybe because of sleep
deprivation :)
I think FILE:FUNCTION:LINE is a good form to provide to users, but it
seems to me that it is incorrect to rewrite a user's "FUNCTION" linespec
into this form. My reason is that it seems like it would do the wrong
thing if the line number changes -- the linespec would stop working,
rather than re-evaluate correctly. How do you deal with this problem?
My patch doesn't provide FILE:FUNCTION:LINE; but Keith is working on
some parsing changes for linespec that should make it simpler to add
things like this in the future.
Joel> The question is, can we use that same form for everyone? I thought
Joel> you were going to do unconditional rewriting of the location string,
Joel> but now I'm not so sure anymore...
With my patch, only relative forms require rewriting. I think those are
just "break LINE" and "break LABEL". The former is rewritten to
FILE:LINE, and the latter to FUNCTION:LABEL.
With multiple-symbols=ask, we also do filtering based on the "canonical
form", which is different from the string used to re-evaluate.
E.g., suppose you do "break something::method" and there are 5 methods.
Suppose you have multiple-symbols=ask and you pick something::method(int).
Then, we will have a breakpoint whose linespec is "something::method"
but whose filter is "something::method(int)".
I chose this somewhat odd design over the more straightforward rewriting
of the linespec because there are canonical forms which are not yet
suitable as input to linespec. I could add these to linespec, but I
wanted to keep the patch smaller -- my plan is to update this once
Keith's changes are ready.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-08 16:36 ` Tom Tromey
2011-11-09 16:05 ` Joel Brobecker
@ 2011-11-09 18:37 ` Tom Tromey
2011-11-14 21:11 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-09 18:37 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> So, I am still against it, but I will take a stab at it if you think it
Tom> is important.
Here is a refresh of this patch. This fixes the regressions noted by
Jan, but also changes ovsrch.exp not to assume that namespace lookups
are done.
In order to preserve existing behavior, I have linespec fall back on
lookup_symbol when current_language==Ada. This is a hack, and I think
it would be nice to do better here. You can search for 'language_ada'
to see the two places where I did this.
Built and regtested on x86-64 F15.
Tom
2011-10-28 Tom Tromey <tromey@redhat.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:
* 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.
* 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.
* 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.
(compare_core_addrs, find_pcs_for_symtab_line): New functions.
(find_line_common): Add 'start' argument.
(decode_line_spec): Update.
* 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.
* source.c (line_info): Set pspace on sal. Check program space in
the loop.
* 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 (struct linespec_sals): New type.
(struct linespec_result) <canonical>: Remove.
<pre_expanded, addr_string, sals>: New fields.
(destroy_linespec_result, make_cleanup_destroy_linespec_result)
(decode_line_list, 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, decode_line_list): 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. Fall back on
decode_variable.
(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.
* 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. 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.
(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.
* block.h (block_containing_function): Declare.
* block.c (block_containing_function): New function.
* skip.c (skip_function_command): Update.
(skip_re_set): Update.
2011-10-28 Tom Tromey <tromey@redhat.com>
* 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/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.
From 55c651d8455e4fef21d88599e8595f1f4f66d561 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 27 Oct 2011 09:26:30 -0600
Subject: [PATCH 2/2] the rewrite
---
gdb/ChangeLog | 150 ++
gdb/block.c | 14 +
gdb/block.h | 2 +
gdb/breakpoint.c | 546 +++----
gdb/breakpoint.h | 21 +-
gdb/cli/cli-cmds.c | 103 +-
gdb/defs.h | 1 +
gdb/dwarf2loc.c | 3 -
gdb/dwarf2read.c | 60 +-
gdb/linespec.c | 2490 +++++++++++++++---------
gdb/linespec.h | 105 +-
gdb/minsyms.c | 40 +
gdb/objc-lang.c | 288 +--
gdb/objc-lang.h | 12 +-
gdb/psymtab.c | 80 +-
gdb/python/py-type.c | 14 +-
gdb/python/python.c | 2 +-
gdb/skip.c | 4 +-
gdb/solib-target.c | 2 -
gdb/source.c | 8 +-
gdb/stack.c | 16 +-
gdb/symfile.h | 34 +-
gdb/symtab.c | 372 +++-
gdb/symtab.h | 34 +
gdb/testsuite/ChangeLog | 32 +
gdb/testsuite/Makefile.in | 2 +-
gdb/testsuite/configure | 3 +-
gdb/testsuite/configure.ac | 2 +-
gdb/testsuite/gdb.base/break.exp | 3 +-
gdb/testsuite/gdb.base/list.exp | 2 +-
gdb/testsuite/gdb.base/sepdebug.exp | 3 +-
gdb/testsuite/gdb.base/solib-symbol.exp | 14 +-
gdb/testsuite/gdb.cp/mb-ctor.exp | 4 +-
gdb/testsuite/gdb.cp/mb-inline.exp | 4 +-
gdb/testsuite/gdb.cp/mb-templates.exp | 6 +-
gdb/testsuite/gdb.cp/method2.exp | 2 +-
gdb/testsuite/gdb.cp/ovldbreak.exp | 79 +-
gdb/testsuite/gdb.cp/ovsrch.exp | 20 +-
gdb/testsuite/gdb.cp/re-set-overloaded.exp | 1 -
gdb/testsuite/gdb.cp/templates.exp | 9 +-
gdb/testsuite/gdb.linespec/Makefile.in | 14 +
gdb/testsuite/gdb.linespec/base/one/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/base/two/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/linespec.exp | 106 +
gdb/testsuite/gdb.linespec/lspec.cc | 13 +
gdb/testsuite/gdb.linespec/lspec.h | 9 +
gdb/testsuite/gdb.objc/objcdecode.exp | 6 +-
gdb/testsuite/gdb.trace/tracecmd.exp | 2 +-
gdb/tracepoint.c | 2 +-
gdb/tui/tui-winsource.c | 47 +-
gdb/utils.c | 11 +
51 files changed, 3052 insertions(+), 1783 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/Makefile.in
create mode 100644 gdb/testsuite/gdb.linespec/base/one/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/base/two/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/linespec.exp
create mode 100644 gdb/testsuite/gdb.linespec/lspec.cc
create mode 100644 gdb/testsuite/gdb.linespec/lspec.h
diff --git a/gdb/block.c b/gdb/block.c
index c165bc2..1fa3688 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -82,6 +82,20 @@ block_linkage_function (const struct block *bl)
return BLOCK_FUNCTION (bl);
}
+/* Return the symbol for the function which contains a specified
+ block, described by a struct block BL. The return value will be
+ the closest enclosing function, which might be an inline
+ function. */
+
+struct symbol *
+block_containing_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
/* Return one if BL represents an inlined function. */
int
diff --git a/gdb/block.h b/gdb/block.h
index 1742f24..63b18a6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -131,6 +131,8 @@ struct blockvector
extern struct symbol *block_linkage_function (const struct block *);
+extern struct symbol *block_containing_function (const struct block *);
+
extern int block_inlined_p (const struct block *block);
extern int contained_in (const struct block *, const struct block *);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8ab09ba..7a7d8ce 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4549,7 +4549,7 @@ print_breakpoint_location (struct breakpoint *b,
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (b->source_file && loc)
+ else if (loc && loc->source_file)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
@@ -4562,7 +4562,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_field_string (uiout, "file", loc->source_file);
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
@@ -4574,7 +4574,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_field_string (uiout, "fullname", fullname);
}
- ui_out_field_int (uiout, "line", b->line_number);
+ ui_out_field_int (uiout, "line", loc->line_number);
}
else if (loc)
{
@@ -5798,12 +5798,10 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sal.symtab->filename);
+ if (sal.symtab != NULL)
+ b->loc->source_file = xstrdup (sal.symtab->filename);
b->loc->section = sal.section;
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
set_breakpoint_location_function (b->loc,
sal.explicit_pc || sal.explicit_line);
@@ -7038,12 +7036,10 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
- if (orig->source_file == NULL)
- copy->source_file = NULL;
- else
- copy->source_file = xstrdup (orig->source_file);
+ if (orig->loc->source_file != NULL)
+ copy->loc->source_file = xstrdup (orig->loc->source_file);
- copy->line_number = orig->line_number;
+ copy->loc->line_number = orig->loc->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
@@ -7116,6 +7112,10 @@ add_location_to_breakpoint (struct breakpoint *b,
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
+ if (sal->symtab != NULL)
+ loc->source_file = xstrdup (sal->symtab->filename);
+ loc->line_number = sal->line;
+
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
return loc;
@@ -7172,7 +7172,7 @@ bp_loc_is_permanent (struct bp_location *loc)
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7286,12 +7286,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
me. */
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->filter = filter;
}
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7314,7 +7315,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- cond_string,
+ filter, cond_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
@@ -7324,138 +7325,6 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
install_breakpoint (internal, b);
}
-/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
- elements to fill the void space. */
-static void
-remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
-{
- int i = index_to_remove+1;
- int last_index = sal->nelts-1;
-
- for (;i <= last_index; ++i)
- sal->sals[i-1] = sal->sals[i];
-
- --(sal->nelts);
-}
-
-/* If appropriate, obtains all sals that correspond to the same file
- and line as SAL, in all program spaces. Users debugging with IDEs,
- will want to set a breakpoint at foo.c:line, and not really care
- about program spaces. This is done only if SAL does not have
- explicit PC and has line and file information. If we got just a
- single expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out all sals for
- which the name of enclosing function is different from SAL. This
- makes sure that if we have breakpoint originally set in template
- instantiation, say foo<int>(), we won't expand SAL to locations at
- the same line in all existing instantiations of 'foo'. */
-
-static struct symtabs_and_lines
-expand_line_sal_maybe (struct symtab_and_line sal)
-{
- struct symtabs_and_lines expanded;
- CORE_ADDR original_pc = sal.pc;
- char *original_function = NULL;
- int found;
- int i;
- struct cleanup *old_chain;
-
- /* If we have explicit pc, don't expand.
- If we have no line number, we can't expand. */
- if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
- {
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sal;
- return expanded;
- }
-
- sal.pc = 0;
-
- old_chain = save_current_space_and_thread ();
-
- switch_to_program_space_and_thread (sal.pspace);
-
- find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
- /* Note that expand_line_sal visits *all* program spaces. */
- expanded = expand_line_sal (sal);
-
- if (expanded.nelts == 1)
- {
- /* We had one sal, we got one sal. Return that sal, adjusting it
- past the function prologue if necessary. */
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- skip_prologue_sal (&expanded.sals[0]);
- do_cleanups (old_chain);
- return expanded;
- }
-
- if (!sal.explicit_line)
- {
- CORE_ADDR func_addr, func_end;
- for (i = 0; i < expanded.nelts; ++i)
- {
- CORE_ADDR pc = expanded.sals[i].pc;
- char *this_function;
-
- /* We need to switch threads as well since we're about to
- read memory. */
- switch_to_program_space_and_thread (expanded.sals[i].pspace);
-
- if (find_pc_partial_function (pc, &this_function,
- &func_addr, &func_end))
- {
- if (this_function
- && strcmp (this_function, original_function) != 0)
- {
- remove_sal (&expanded, i);
- --i;
- }
- }
- }
- }
-
- /* Skip the function prologue if necessary. */
- for (i = 0; i < expanded.nelts; ++i)
- skip_prologue_sal (&expanded.sals[i]);
-
- do_cleanups (old_chain);
-
- if (expanded.nelts <= 1)
- {
- /* This is an ugly workaround. If we get zero expanded sals
- then something is really wrong. Fix that by returning the
- original sal. */
-
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- return expanded;
- }
-
- if (original_pc)
- {
- found = 0;
- for (i = 0; i < expanded.nelts; ++i)
- if (expanded.sals[i].pc == original_pc)
- {
- found = 1;
- break;
- }
- gdb_assert (found);
- }
-
- return expanded;
-}
-
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
@@ -7473,7 +7342,6 @@ expand_line_sal_maybe (struct symtab_and_line sal)
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals,
struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
@@ -7482,17 +7350,30 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
int enabled, int internal)
{
int i;
+ struct linespec_sals *lsal;
- for (i = 0; i < sals.nelts; ++i)
+ if (canonical->pre_expanded)
+ gdb_assert (VEC_length (linespec_sals, canonical->sals) == 1);
+
+ for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
{
- struct symtabs_and_lines expanded =
- expand_line_sal_maybe (sals.sals[i]);
+ /* Note that 'addr_string' can be NULL in the case of a plain
+ 'break', without arguments. */
+ char *addr_string = (canonical->addr_string
+ ? xstrdup (canonical->addr_string)
+ : NULL);
+ char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
+ struct cleanup *inner = make_cleanup (xfree, addr_string);
- create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
+ make_cleanup (xfree, filter_string);
+ create_breakpoint_sal (gdbarch, lsal->sals,
+ addr_string,
+ filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
canonical->special_display);
+ discard_cleanups (inner);
}
}
@@ -7506,7 +7387,6 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (char **address,
- struct symtabs_and_lines *sals,
struct linespec_result *canonical)
{
char *addr_start = *address;
@@ -7520,10 +7400,11 @@ parse_breakpoint_sals (char **address,
address. */
if (last_displayed_sal_is_valid ())
{
+ struct linespec_sals lsal;
struct symtab_and_line sal;
init_sal (&sal); /* Initialize to zeroes. */
- sals->sals = (struct symtab_and_line *)
+ lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
/* Set sal's pspace, pc, symtab, and line to the values
@@ -7538,8 +7419,11 @@ parse_breakpoint_sals (char **address,
instances with the same symtab and line. */
sal.explicit_pc = 1;
- sals->sals[0] = sal;
- sals->nelts = 1;
+ lsal.sals.sals[0] = sal;
+ lsal.sals.nelts = 1;
+ lsal.canonical = NULL;
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
else
error (_("No default breakpoint address now."));
@@ -7549,40 +7433,15 @@ parse_breakpoint_sals (char **address,
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving the last displayed codepoint pointers
- alone.
-
- ObjC: However, don't match an Objective-C method name which
- may have a '+' or '-' succeeded by a '[' */
-
- struct symtab_and_line cursal = get_current_source_symtab_and_line ();
-
- if (last_displayed_sal_is_valid ()
- && (!cursal.symtab
- || ((strchr ("+-", (*address)[0]) != NULL)
- && ((*address)[1] != '['))))
- *sals = decode_line_1 (address, 1,
- get_last_displayed_symtab (),
- get_last_displayed_line (),
- canonical);
+ time while leaving default_breakpoint_* alone. */
+ if (last_displayed_sal_is_valid ())
+ decode_line_full (address, 1,
+ get_last_displayed_symtab (),
+ get_last_displayed_line (),
+ canonical, NULL, NULL);
else
- *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- canonical);
- }
- /* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && canonical->canonical == NULL)
- canonical->canonical = xcalloc (sals->nelts, sizeof (char *));
- if (addr_start != (*address))
- {
- int i;
-
- for (i = 0; i < sals->nelts; i++)
- {
- /* Add the string if not present. */
- if (canonical->canonical[i] == NULL)
- canonical->canonical[i] = savestring (addr_start,
- (*address) - addr_start);
- }
+ decode_line_full (address, 1, (struct symtab *) NULL, 0,
+ canonical, NULL, NULL);
}
}
@@ -7617,15 +7476,20 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
for (i = 0; i < sals->nelts; i++)
{
+ struct gdbarch *sarch;
+
sal = &sals->sals[i];
- rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ sarch = get_sal_arch (*sal);
+ if (sarch == NULL)
+ sarch = gdbarch;
+ rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
NULL, &msg);
old_chain = make_cleanup (xfree, msg);
if (!rslt)
error (_("May not have a fast tracepoint at 0x%s%s"),
- paddress (gdbarch, sal->pc), (msg ? msg : ""));
+ paddress (sarch, sal->pc), (msg ? msg : ""));
do_cleanups (old_chain);
}
@@ -7767,8 +7631,6 @@ create_breakpoint (struct gdbarch *gdbarch,
int from_tty, int enabled, int internal)
{
volatile struct gdb_exception e;
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
char *copy_arg;
char *addr_start = arg;
struct linespec_result canonical;
@@ -7781,26 +7643,26 @@ create_breakpoint (struct gdbarch *gdbarch,
gdb_assert (ops != NULL);
- sals.sals = NULL;
- sals.nelts = 0;
init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
int i;
+ struct linespec_sals lsal;
- sals = decode_static_tracepoint_spec (&arg);
+ lsal.sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
- for (i = 0; i < sals.nelts; i++)
- canonical.canonical[i] = xstrdup (copy_arg);
+
+ lsal.canonical = xstrdup (copy_arg);
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+
goto done;
}
TRY_CATCH (e, RETURN_MASK_ALL)
{
- parse_breakpoint_sals (&arg, &sals, &canonical);
+ parse_breakpoint_sals (&arg, &canonical);
}
/* If caller is interested in rc value from parse, set value. */
@@ -7832,35 +7694,31 @@ create_breakpoint (struct gdbarch *gdbarch,
a pending breakpoint and selected yes, or pending
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
- copy_arg = xstrdup (addr_start);
- canonical.canonical = ©_arg;
- sals.nelts = 1;
- sals.sals = &pending_sal;
- pending_sal.pc = 0;
- pending = 1;
+ {
+ struct linespec_sals lsal;
+
+ copy_arg = xstrdup (addr_start);
+ lsal.canonical = xstrdup (copy_arg);
+ lsal.sals.nelts = 1;
+ lsal.sals.sals = XNEW (struct symtab_and_line);
+ init_sal (&lsal.sals.sals[0]);
+ pending = 1;
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+ }
break;
default:
throw_exception (e);
}
break;
default:
- if (!sals.nelts)
+ if (VEC_empty (linespec_sals, canonical.sals))
return 0;
}
done:
/* Create a chain of things that always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- if (!pending)
- {
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the canonical array but not its contents. */
- make_cleanup (xfree, canonical.canonical);
- }
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
@@ -7868,28 +7726,36 @@ create_breakpoint (struct gdbarch *gdbarch,
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the canonical for cleanup. These go on
- the bkpt_chain and only occur if the breakpoint create fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (canonical.canonical[i] != NULL)
- make_cleanup (xfree, canonical.canonical[i]);
- }
-
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ breakpoint_sals_to_pc (&iter->sals);
+ }
/* Fast tracepoints may have additional restrictions on location. */
if (type_wanted == bp_fast_tracepoint)
- check_fast_tracepoint_sals (gdbarch, &sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ check_fast_tracepoint_sals (gdbarch, &iter->sals);
+ }
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
if (!pending)
{
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+
if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
@@ -7898,7 +7764,7 @@ create_breakpoint (struct gdbarch *gdbarch,
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
&thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
@@ -7920,24 +7786,26 @@ create_breakpoint (struct gdbarch *gdbarch,
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (canonical.canonical[0]))
+ && is_marker_spec (lsal->canonical))
{
int i;
- for (i = 0; i < sals.nelts; ++i)
+ for (i = 0; i < lsal->sals.nelts; ++i)
{
struct symtabs_and_lines expanded;
struct tracepoint *tp;
struct cleanup *old_chain;
+ char *addr_string;
expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sals.sals[i];
- old_chain = make_cleanup (xfree, expanded.sals);
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical.addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
- canonical.canonical[i],
+ addr_string, NULL,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
@@ -7953,11 +7821,11 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, &tp->base);
- do_cleanups (old_chain);
+ discard_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
+ create_breakpoints_sal (gdbarch, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
@@ -7972,7 +7840,7 @@ create_breakpoint (struct gdbarch *gdbarch,
b = set_raw_breakpoint_without_location (gdbarch, type_wanted, ops);
set_breakpoint_number (internal, b);
b->thread = -1;
- b->addr_string = canonical.canonical[0];
+ b->addr_string = copy_arg;
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
@@ -7989,7 +7857,7 @@ create_breakpoint (struct gdbarch *gdbarch,
observer_notify_breakpoint_created (b);
}
- if (sals.nelts > 1)
+ if (VEC_length (linespec_sals, canonical.sals) > 1)
{
warning (_("Multiple breakpoints were set.\nUse the "
"\"delete\" command to delete unwanted breakpoints."));
@@ -8370,8 +8238,8 @@ break_range_command (char *arg, int from_tty)
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
- struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
+ struct linespec_sals *lsal_start, *lsal_end;
/* We don't support software ranged breakpoints. */
if (target_ranged_break_num_registers () < 0)
@@ -8384,71 +8252,58 @@ break_range_command (char *arg, int from_tty)
if (can_use_bp < 0)
error (_("Hardware breakpoints used exceeds limit."));
+ arg = skip_spaces (arg);
if (arg == NULL || arg[0] == '\0')
error(_("No address range specified."));
- sals_start.sals = NULL;
- sals_start.nelts = 0;
init_linespec_result (&canonical_start);
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ parse_breakpoint_sals (&arg, &canonical_start);
- parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
-
- sal_start = sals_start.sals[0];
- addr_string_start = canonical_start.canonical[0];
- cleanup_bkpt = make_cleanup (xfree, addr_string_start);
- xfree (sals_start.sals);
- xfree (canonical_start.canonical);
+ cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
if (arg[0] != ',')
error (_("Too few arguments."));
- else if (sals_start.nelts == 0)
+ else if (VEC_empty (linespec_sals, canonical_start.sals))
error (_("Could not find location of the beginning of the range."));
- else if (sals_start.nelts != 1)
+
+ lsal_start = VEC_index (linespec_sals, canonical_start.sals, 0);
+
+ if (VEC_length (linespec_sals, canonical_start.sals) > 1
+ || lsal_start->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_start);
+ sal_start = lsal_start->sals.sals[0];
+ addr_string_start = lsal_start->canonical;
arg++; /* Skip the comma. */
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ arg = skip_spaces (arg);
/* Parse the end location. */
- sals_end.sals = NULL;
- sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
- /* We call decode_line_1 directly here instead of using
+ /* We call decode_line_full directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
- sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
- &canonical_end);
-
- /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
- if (canonical_end.canonical == NULL)
- canonical_end.canonical = xcalloc (1, sizeof (char *));
- /* Add the string if not present. */
- if (arg_start != arg && canonical_end.canonical[0] == NULL)
- canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
-
- sal_end = sals_end.sals[0];
- addr_string_end = canonical_end.canonical[0];
- make_cleanup (xfree, addr_string_end);
- xfree (sals_end.sals);
- xfree (canonical_end.canonical);
-
- if (sals_end.nelts == 0)
+ decode_line_full (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end, NULL, NULL);
+
+ make_cleanup_destroy_linespec_result (&canonical_end);
+
+ if (VEC_empty (linespec_sals, canonical_end.sals))
error (_("Could not find location of the end of the range."));
- else if (sals_end.nelts != 1)
+
+ lsal_end = VEC_index (linespec_sals, canonical_end.sals, 0);
+ if (VEC_length (linespec_sals, canonical_end.sals) > 1
+ || lsal_end->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_end);
+ sal_end = lsal_end->sals.sals[0];
+ addr_string_end = lsal_end->canonical;
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
@@ -8475,11 +8330,11 @@ break_range_command (char *arg, int from_tty)
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
- b->addr_string = addr_string_start;
- b->addr_string_range_end = addr_string_end;
+ b->addr_string = xstrdup (addr_string_start);
+ b->addr_string_range_end = xstrdup (addr_string_end);
b->loc->length = length;
- discard_cleanups (cleanup_bkpt);
+ do_cleanups (cleanup_bkpt);
mention (b);
observer_notify_breakpoint_created (b);
@@ -9588,10 +9443,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&arg, 1,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
@@ -10174,18 +10028,21 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
- && (loc->pspace == sal.pspace)
- && (loc->address == sal.pc)
- && (!section_is_overlay (loc->section)
- || loc->section == sal.section);
- int line_match = ((default_match || (0 == sal.pc))
- && b->source_file != NULL
+ /* If the user specified file:line, don't allow a PC
+ match. This matches historical gdb behavior. */
+ int pc_match = (!sal.explicit_line
+ && sal.pc
+ && (loc->pspace == sal.pspace)
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section));
+ int line_match = ((default_match || sal.explicit_line)
+ && loc->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && filename_cmp (b->source_file,
+ && filename_cmp (loc->source_file,
sal.symtab->filename) == 0
- && b->line_number == sal.line);
+ && loc->line_number == sal.line);
if (pc_match || line_match)
{
match = 1;
@@ -10721,15 +10578,25 @@ say_where (struct breakpoint *b)
}
else
{
- if (opts.addressprint || b->source_file == NULL)
+ if (opts.addressprint || b->loc->source_file == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
if (b->loc->next)
{
@@ -10749,6 +10616,7 @@ bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
xfree (self->function_name);
+ xfree (self->source_file);
}
static const struct bp_location_ops bp_location_ops =
@@ -10765,8 +10633,8 @@ base_breakpoint_dtor (struct breakpoint *self)
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
xfree (self->addr_string);
+ xfree (self->filter);
xfree (self->addr_string_range_end);
- xfree (self->source_file);
}
static struct bp_location *
@@ -11597,17 +11465,18 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
ui_out_field_int (uiout, "line", sal.line);
ui_out_text (uiout, "\n");
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
- xfree (b->source_file);
+ xfree (b->loc->source_file);
if (sym)
- b->source_file = xstrdup (sal.symtab->filename);
+ b->loc->source_file = xstrdup (sal.symtab->filename);
else
- b->source_file = NULL;
+ b->loc->source_file = NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal.symtab->filename, b->line_number);
+ sal.symtab->filename,
+ b->loc->line_number);
/* Might be nice to check if function changed, and warn if
so. */
@@ -11657,8 +11526,17 @@ update_breakpoint_locations (struct breakpoint *b,
int i;
struct bp_location *existing_locations = b->loc;
- /* Ranged breakpoints have only one start location and one end location. */
- gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+ if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
+ {
+ /* Ranged breakpoints have only one start location and one end
+ location. */
+ b->enable_state = bp_disabled;
+ update_global_location_list (1);
+ printf_unfiltered (_("Could not reset ranged breakpoint %d: "
+ "multiple locations found\n"),
+ b->number);
+ return;
+ }
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
@@ -11673,8 +11551,11 @@ update_breakpoint_locations (struct breakpoint *b,
for (i = 0; i < sals.nelts; ++i)
{
- struct bp_location *new_loc =
- add_location_to_breakpoint (b, &(sals.sals[i]));
+ struct bp_location *new_loc;
+
+ switch_to_program_space_and_thread (sals.sals[i].pspace);
+
+ new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
/* Reparse conditions, they might contain references to the
old symtab. */
@@ -11698,16 +11579,6 @@ update_breakpoint_locations (struct breakpoint *b,
}
}
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sals.sals[i].symtab->filename);
-
- if (b->line_number == 0)
- b->line_number = sals.sals[i].line;
-
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
@@ -11774,7 +11645,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
char *s;
int marker_spec;
struct symtabs_and_lines sals = {0};
- struct gdb_exception e;
+ volatile struct gdb_exception e;
s = addr_string;
marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
@@ -11795,7 +11666,30 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
error (_("marker %s not found"), tp->static_trace_marker_id);
}
else
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ {
+ struct linespec_result canonical;
+
+ init_linespec_result (&canonical);
+ decode_line_full (&s, 1, (struct symtab *) NULL, 0,
+ &canonical, multiple_symbols_all,
+ b->filter);
+
+ /* We should get 0 or 1 resulting SALs. */
+ gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
+
+ if (VEC_length (linespec_sals, canonical.sals) > 0)
+ {
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ sals = lsal->sals;
+ /* Arrange it so the destructor does not free the
+ contents. */
+ lsal->sals.sals = NULL;
+ }
+
+ destroy_linespec_result (&canonical);
+ }
}
if (e.reason < 0)
{
@@ -11829,9 +11723,10 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
{
- gdb_assert (sals.nelts == 1);
+ int i;
- resolve_sal_pc (&sals.sals[0]);
+ for (i = 0; i < sals.nelts; ++i)
+ resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
char *cond_string = 0;
@@ -11874,7 +11769,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals.sals);
- expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = sals;
}
if (b->addr_string_range_end)
@@ -11883,7 +11778,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals_end.sals);
- expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ expanded_end = sals_end;
}
}
@@ -12421,11 +12316,10 @@ decode_line_spec_1 (char *string, int funfirstline)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&string, funfirstline,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, NULL);
+ (struct symtab *) NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 94e324a..bb99600 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -393,6 +393,14 @@ struct bp_location
This variable keeps a number of events still to go, when
it becomes 0 this location is retired. */
int events_till_retirement;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ char *source_file;
};
/* This structure is a collection of function pointers that, if available,
@@ -540,14 +548,6 @@ struct breakpoint
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
- /* Line number of this address. */
-
- int line_number;
-
- /* Source file name of this address. */
-
- char *source_file;
-
/* Non-zero means a silent breakpoint (don't print frame info
if we stop here). */
unsigned char silent;
@@ -571,6 +571,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
+ /* The filter that should be passed to decode_line_full when
+ re-setting this breakpoint. This may be NULL, but otherwise is
+ allocated with xmalloc. */
+ char *filter;
+
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 94328c4..bc76864 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -92,6 +92,9 @@ void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
@@ -246,16 +249,6 @@ help_command (char *command, int from_tty)
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
@@ -796,8 +789,9 @@ edit_command (char *arg, int from_tty)
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
@@ -926,8 +920,9 @@ list_command (char *arg, int from_tty)
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
@@ -959,9 +954,10 @@ list_command (char *arg, int from_tty)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals_end = decode_line_list (&arg1, 0, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ sals_end = decode_line_list (&arg1, 0, sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
@@ -1472,6 +1468,85 @@ ambiguous_line_spec (struct symtabs_and_lines *sals)
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ || sals->sals[i].symtab == NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
diff --git a/gdb/defs.h b/gdb/defs.h
index d0b6813..0e6e629 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -428,6 +428,7 @@ char *ldirname (const char *filename);
char **gdb_buildargv (const char *);
int compare_positive_ints (const void *ap, const void *bp);
+int compare_strings (const void *ap, const void *bp);
/* A wrapper for bfd_errmsg to produce a more helpful error message
in the case of bfd_error_file_ambiguously recognized.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8a7d7e9..7547a40 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -443,9 +443,6 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
return sym;
}
-/* Define VEC (CORE_ADDR) functions. */
-DEF_VEC_I (CORE_ADDR);
-
/* Verify function with entry point exact address ADDR can never call itself
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
can call itself via tail calls.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 84eb589..145c8d0 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2438,10 +2438,38 @@ dw2_forget_cached_source_info (struct objfile *objfile)
dw2_free_cached_file_names, NULL);
}
+/* Helper function for dw2_map_symtabs_matching_filename that expands
+ the symtabs and calls the iterator. */
+
+static int
+dw2_map_expand_apply (struct objfile *objfile,
+ struct dwarf2_per_cu_data *per_cu,
+ const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded CUs. */
+ if (per_cu->v.quick->symtab)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ dw2_instantiate_symtab (objfile, per_cu);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
static int
-dw2_lookup_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
+dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
{
int i;
int check_basename = lbasename (name) == name;
@@ -2469,8 +2497,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (FILENAME_CMP (name, this_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
if (check_basename && ! base_cu
@@ -2485,8 +2515,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (full_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
@@ -2498,8 +2530,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
}
@@ -2507,8 +2541,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (base_cu)
{
- *result = dw2_instantiate_symtab (objfile, base_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, base_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
return 0;
@@ -2850,7 +2886,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
- dw2_lookup_symtab,
+ dw2_map_symtabs_matching_filename,
dw2_lookup_symbol,
dw2_pre_expand_symtabs_matching,
dw2_print_stats,
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 37ec368..38a10cb 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -44,108 +44,246 @@
#include <ctype.h>
#include "cli/cli-utils.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_variable (struct linespec_state *self,
+ char *copy);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symtab *symtab_from_filename (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 symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+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_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+/* Helper functions. */
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Add SAL to SALS. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+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 decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* 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 symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+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);
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+ if (self->canonical)
+ {
+ char *canonical_name = NULL;
-/* Helper functions. */
+ self->canonical_names = xrealloc (self->canonical_names,
+ sals->nelts * sizeof (char *));
+ if (sal->symtab && sal->symtab->filename)
+ {
+ char *filename = sal->symtab->filename;
+
+ /* FIXME: this is where we should do "FILE:FUNCTION:LINE",
+ to let us distinguish between different template
+ instantiations. */
+ 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
@@ -180,26 +318,64 @@ 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 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 (strcmp_iw (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;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
+ if (pspace->executing_startup)
+ continue;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ set_current_program_space (pspace);
- return count;
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+ iterate_name_matcher,
+ ALL_DOMAIN,
+ &name);
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ iterate_over_symbols (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -226,40 +402,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);
@@ -287,181 +447,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;
-}
-
-/* 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;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-
-
/* 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 ','
@@ -517,147 +528,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
{
@@ -665,14 +683,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". */
@@ -812,13 +826,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
@@ -835,21 +846,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);
@@ -876,7 +892,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)
@@ -902,10 +925,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? */
@@ -933,14 +958,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);
@@ -953,12 +980,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. */
@@ -973,9 +1004,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. */
@@ -998,10 +1030,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). */
@@ -1041,91 +1078,239 @@ 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;
+ }
}
-\f
+/* A constructor for linespec_state. */
-/* 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. */
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int funfirstline,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = funfirstline;
+ 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);
+}
-/* First, some functions to initialize stuff at the beggining of the
- function. */
+/* A destructor for linespec_state. */
static void
-initialize_defaults (struct symtab **default_symtab, int *default_line)
+linespec_state_destructor (void *arg)
{
- if (*default_symtab == 0)
- {
- /* Use whatever we have for the default source line. We don't use
- get_current_or_default_symtab_and_line as it can recurse and call
- us back! */
- struct symtab_and_line cursal =
- get_current_source_symtab_and_line ();
-
- *default_symtab = cursal.symtab;
- *default_line = cursal.line;
- }
-}
+ struct linespec_state *self = arg;
-\f
+ xfree (self->user_filename);
+ xfree (self->user_function);
+ VEC_free (symtab_p, self->file_symtabs);
+ htab_delete (self->addr_set);
+}
-/* Decode arg of the form *PC. */
+/* See linespec.h. */
-static struct symtabs_and_lines
-decode_indirect (char **argptr)
+void
+decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter)
{
- struct symtabs_and_lines values;
- CORE_ADDR pc;
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+ char *arg_start = *argptr;
+
+ 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);
+
+ linespec_state_constructor (&state, funfirstline, 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;
+
+ 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)
+ {
+ VEC (const_char_ptr) *filters = 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 funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, 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;
+}
+
+/* See linespec.h. */
+
+struct symtabs_and_lines
+decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, default_symtab,
+ default_line, NULL);
+ state.list_mode = 1;
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+\f
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+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));
@@ -1138,6 +1323,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;
}
@@ -1235,8 +1423,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)
@@ -1264,94 +1451,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)
+ if (self->canonical)
{
- /* 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
- {
- /* 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,
- ¤t_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
@@ -1360,9 +1505,8 @@ 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;
@@ -1370,10 +1514,9 @@ decode_compound (char **argptr, int funfirstline,
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. */
@@ -1408,8 +1551,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
@@ -1509,15 +1651,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
@@ -1567,9 +1708,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. */
@@ -1579,8 +1718,10 @@ 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. */
@@ -1600,7 +1741,6 @@ decode_compound (char **argptr, int funfirstline,
/* Look up entire name. */
name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
@@ -1608,213 +1748,400 @@ decode_compound (char **argptr, int funfirstline,
make_cleanup (xfree, name);
}
- 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;
+ return decode_variable (self, copy);
+}
- /* 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);
- }
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* 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);
-}
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
+
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
-/* Next come some helper functions for decode_compound. */
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
+
+ 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);
+ }
+
+ 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);
+ iterate_over_symbols (search_block, copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ 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;
- /* Find all methods with a matching name, and put them in
- sym_arr. */
+ uia = (uintptr_t) *sa;
+ uib = (uintptr_t) *sb;
- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
- file_symtab);
+ if (uia < uib)
+ return -1;
+ if (uia > uib)
+ return 1;
+
+ return 0;
+}
- /* 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)
+/* 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);
+}
+
+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);
+
+ 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);
+}
+
+\f
+
+/* 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;
}
-\f
+/* 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);
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+ /* Find that file's data. */
+ ALL_PSPACES (pspace)
+ {
+ if (pspace->executing_startup)
+ continue;
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+ set_current_program_space (pspace);
+ iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+ }
+
+ 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 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] == '"')
@@ -1823,9 +2150,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,
@@ -1836,31 +2163,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);
+
+ 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 file_symtab;
+ 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] == '"')
@@ -1869,18 +2212,40 @@ 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 looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (VEC_empty (symbolp, result)
+ && current_language->la_language == language_ada)
+ {
+ struct symbol *function_symbol;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ xfree (copy);
+ copy = xstrdup (SYMBOL_SEARCH_NAME (function_symbol));
+ *user_function = copy;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols,
+ &result, NULL);
+ }
+ }
+
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ return result;
}
\f
@@ -1890,13 +2255,16 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
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 ix;
+ struct symtab *elt;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1904,12 +2272,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
@@ -1917,11 +2282,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 == '+')
@@ -1934,14 +2307,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;
@@ -1949,28 +2322,77 @@ 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);
+
+ 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));
+
+ if (self->list_mode)
+ {
+ /* 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);
+ }
+ else
+ {
+ int pcix;
+ CORE_ADDR pc;
+ VEC (CORE_ADDR) *pcs;
+
+ pcs = find_pcs_for_symtab_line (elt, val.line);
+ if (VEC_empty (CORE_ADDR, pcs))
+ continue;
+
+ for (pcix = 0; VEC_iterate (CORE_ADDR, pcs, pcix, pc); ++pcix)
+ {
+ val.symtab = elt;
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = pc;
+ val.explicit_line = 1;
+
+ skip_prologue_sal (&val);
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
+
+ VEC_free (CORE_ADDR, pcs);
+ }
+ }
+
+ 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;
}
@@ -1979,17 +2401,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')
@@ -2011,19 +2433,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 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.reason == 0)
+ return values;
+
+ 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))
@@ -2033,18 +2454,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;
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ 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;
}
@@ -2053,7 +2493,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.
@@ -2062,78 +2502,308 @@ 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)
{
+ 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_selected_block (0);
+
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;
+ }
+
+ 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)
+ {
+ 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);
+ }
}
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+ if (self->canonical && result->nelts > 0)
+ {
+ self->canonical->pre_expanded = 1;
+ self->canonical->special_display = 1;
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+ gdb_assert (self->user_function);
+ self->canonical->addr_string
+ = xstrprintf ("%s:%s", self->user_function, copy);
+ }
- return sym != NULL;
+ 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, ¤t_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));
+ 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);
+ 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);
+
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
- name = canon;
- make_cleanup (xfree, name);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (sym != NULL)
+ /* If looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (info.result.nelts == 0 && current_language->la_language == language_ada)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
- }
+ struct symbol *sym;
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ sym = lookup_symbol (lookup_name, get_selected_block (0), VAR_DOMAIN, 0);
+ if (sym)
+ {
+ copy = SYMBOL_SEARCH_NAME (sym);
+ add_matching_symbols_to_info (copy, &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);
}
@@ -2142,130 +2812,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,
- ¤t_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;
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+ 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);
+}
- values.nelts = 1;
- return values;
+/* Cleanup function for a linespec_result. */
+
+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);
}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 3c86af3..d32f401 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -20,8 +20,30 @@
struct symtab;
+#include "vec.h"
+
+/* decode_line_full returns a vector of these. */
+
+struct linespec_sals
+{
+ /* This is the linespec corresponding to the sals contained in this
+ object. It can be passed as the FILTER argument to future calls
+ to decode_line_full. This is freed by
+ destroy_linespec_result. */
+ char *canonical;
+
+ /* Sals. The 'sals' field is destroyed by
+ destroy_linespec_result. */
+ struct symtabs_and_lines sals;
+};
+
+typedef struct linespec_sals linespec_sals;
+DEF_VEC_O (linespec_sals);
+
/* An instance of this may be filled in by decode_line_1. The caller
- must call init_linespec_result to initialize it. */
+ must call init_linespec_result to initialize it and
+ destroy_linespec_result to destroy it. The caller must make copies
+ of any data that it needs to keep. */
struct linespec_result
{
@@ -30,22 +52,85 @@ struct linespec_result
display mechanism would do the wrong thing. */
int special_display;
- /* If non-NULL, an array of canonical names for returned
- symtab_and_line objects. The array has as many elements as the
- `nelts' field in the symtabs_and_line returned by decode_line_1.
- An element in the array may be NULL. The array and each non-NULL
- element in it are allocated with xmalloc and must be freed by the
- caller. */
- char **canonical;
+ /* If non-zero, the linespec result should be considered to be a
+ "pre-expanded" multi-location linespec. A pre-expanded linespec
+ holds all matching locations in a single linespec_sals
+ object. */
+ int pre_expanded;
+
+ /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+ by the user. This will be freed by destroy_linespec_result. */
+ char *addr_string;
+
+ /* The sals. The vector will be freed by
+ destroy_linespec_result. */
+ VEC (linespec_sals) *sals;
};
/* Initialize a linespec_result. */
extern void init_linespec_result (struct linespec_result *);
+/* Destroy a linespec_result. */
+
+extern void destroy_linespec_result (struct linespec_result *);
+
+/* Return a cleanup that destroys a linespec_result. */
+
+extern struct cleanup *
+ make_cleanup_destroy_linespec_result (struct linespec_result *);
+
extern struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline,
- struct symtab *default_symtab, int default_line,
- struct linespec_result *canonical);
+ struct symtab *default_symtab, int default_line);
+
+/* Like decode_line_1, but useful only for the 'list' command. With
+ this variant, a "file:line" linespec will always return a result. */
+
+extern struct symtabs_and_lines
+ decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line);
+
+/* Parse *ARGPTR as a linespec and return results. This is the "full"
+ interface to this module, which handles multiple results
+ properly.
+
+ FUNFIRSTLINE is nonzero if we want the resulting SALs to describe
+ the first line of indicated functions.
+
+ DEFAULT_SYMTAB and DEFAULT_LINE describe the default location.
+ DEFAULT_SYMTAB can be NULL, in which case the current symtab and
+ line are used.
+
+ CANONICAL is where the results are stored. It must not be NULL.
+
+ SELECT_MODE must be one of the multiple_symbols_* constants, or
+ NULL. It determines how multiple results will be handled. If
+ NULL, the appropriate CLI value will be used.
+
+ FILTER can either be NULL or a string holding a canonical name.
+ This is only valid when SELECT_MODE is multiple_symbols_all.
+
+ Multiple results are handled differently depending on the
+ arguments:
+
+ . With multiple_symbols_cancel, an exception is thrown.
+
+ . With multiple_symbols_ask, a menu is presented to the user. The
+ user may select none, in which case an exception is thrown; or all,
+ which is handled like multiple_symbols_all, below. Otherwise,
+ CANONICAL->SALS will have one entry for each name the user chose.
+
+ . With multiple_symbols_all, CANONICAL->SALS will have a single
+ entry describing all the matching locations. If FILTER is
+ non-NULL, then only locations whose canonical name is equal (in the
+ strcmp sense) to FILTER will be returned; all others will be
+ filtered out. */
+
+extern void decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter);
#endif /* defined (LINESPEC_H) */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 70871cd..f90f036 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -310,6 +310,46 @@ lookup_minimal_symbol (const char *name, const char *sfile,
return NULL;
}
+/* Iterate over all the minimal symbols in the objfile OBJF which
+ match NAME. Both the ordinary and demangled names of each symbol
+ are considered. The caller is responsible for canonicalizing NAME,
+ should that need to be done.
+
+ For each matching symbol, CALLBACK is called with the symbol and
+ USER_DATA as arguments. */
+
+void
+iterate_over_minimal_symbols (struct objfile *objf, const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data)
+{
+ unsigned int hash;
+ struct minimal_symbol *iter;
+ int (*cmp) (const char *, const char *);
+
+ /* The first pass is over the ordinary hash table. */
+ hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_hash[hash];
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+ while (iter)
+ {
+ if (cmp (SYMBOL_LINKAGE_NAME (iter), name) == 0)
+ (*callback) (iter, user_data);
+ iter = iter->hash_next;
+ }
+
+ /* The second pass is over the demangled table. */
+ hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_demangled_hash[hash];
+ while (iter)
+ {
+ if (SYMBOL_MATCHES_SEARCH_NAME (iter, name))
+ (*callback) (iter, user_data);
+ iter = iter->demangled_hash_next;
+ }
+}
+
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a pointer
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 592b52e..dcf9459 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -952,49 +952,7 @@ classes_info (char *regexp, int from_tty)
printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
-/*
- * Function: find_imps (char *selector, struct symbol **sym_arr)
- *
- * Input: a string representing a selector
- * a pointer to an array of symbol pointers
- * possibly a pointer to a symbol found by the caller.
- *
- * Output: number of methods that implement that selector. Side
- * effects: The array of symbol pointers is filled with matching syms.
- *
- * By analogy with function "find_methods" (symtab.c), builds a list
- * of symbols matching the ambiguous input, so that "decode_line_2"
- * (symtab.c) can list them and ask the user to choose one or more.
- * In this case the matches are objective c methods
- * ("implementations") matching an objective c selector.
- *
- * Note that it is possible for a normal (c-style) function to have
- * the same name as an objective c selector. To prevent the selector
- * from eclipsing the function, we allow the caller (decode_line_1) to
- * search for such a function first, and if it finds one, pass it in
- * to us. We will then integrate it into the list. We also search
- * for one here, among the minsyms.
- *
- * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
- * into two parts: debuggable (struct symbol) syms, and
- * non_debuggable (struct minimal_symbol) syms. The debuggable
- * ones will come first, before NUM_DEBUGGABLE (which will thus
- * be the index of the first non-debuggable one).
- */
-
-/*
- * Function: total_number_of_imps (char *selector);
- *
- * Input: a string representing a selector
- * Output: number of methods that implement that selector.
- *
- * By analogy with function "total_number_of_methods", this allows
- * decode_line_1 (symtab.c) to detect if there are objective c methods
- * matching the input, and to allocate an array of pointers to them
- * which can be manipulated by "decode_line_2" (also in symtab.c).
- */
-
-char *
+static char *
parse_selector (char *method, char **selector)
{
char *s1 = NULL;
@@ -1050,7 +1008,7 @@ parse_selector (char *method, char **selector)
return s2;
}
-char *
+static char *
parse_method (char *method, char *type, char **class,
char **category, char **selector)
{
@@ -1154,15 +1112,11 @@ parse_method (char *method, char *type, char **class,
}
static void
-find_methods (struct symtab *symtab, char type,
- const char *class, const char *category,
- const char *selector, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+find_methods (char type, const char *class, const char *category,
+ const char *selector,
+ VEC (const_char_ptr) **symbol_names)
{
struct objfile *objfile = NULL;
- struct minimal_symbol *msymbol = NULL;
- struct block *block = NULL;
- struct symbol *sym = NULL;
char *symname = NULL;
@@ -1171,21 +1125,15 @@ find_methods (struct symtab *symtab, char type,
char *ncategory = NULL;
char *nselector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
static char *tmp = NULL;
static unsigned int tmplen = 0;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
-
- if (symtab)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ gdb_assert (symbol_names != NULL);
ALL_OBJFILES (objfile)
{
unsigned int *objc_csym;
+ struct minimal_symbol *msymbol = NULL;
/* The objfile_csym variable counts the number of ObjC methods
that this objfile defines. We save that count as a private
@@ -1202,7 +1150,6 @@ find_methods (struct symtab *symtab, char type,
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
QUIT;
@@ -1216,18 +1163,8 @@ find_methods (struct symtab *symtab, char type,
/* Not a method name. */
continue;
- /* 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, pc,
- ¤t_target);
-
objfile_csym++;
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
/* Now that thinks are a bit sane, clean up the symname. */
while ((strlen (symname) + 1) >= tmplen)
{
@@ -1255,41 +1192,9 @@ find_methods (struct symtab *symtab, char type,
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
- sym = find_pc_function (pc);
- if (sym != NULL)
- {
- const char *newsymname = SYMBOL_NATURAL_NAME (sym);
-
- if (strcmp (symname, newsymname) == 0)
- {
- /* Found a high-level method sym: swap it into the
- lower part of sym_arr (below num_debuggable). */
- if (syms != NULL)
- {
- syms[csym] = syms[cdebug];
- syms[cdebug] = sym;
- }
- csym++;
- cdebug++;
- }
- else
- {
- warning (
-"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
- newsymname, symname);
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
- }
- else
- {
- /* Found a non-debuggable method symbol. */
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
+ VEC_safe_push (const_char_ptr, *symbol_names, symname);
}
+
if (objc_csym == NULL)
{
objc_csym = obstack_alloc (&objfile->objfile_obstack,
@@ -1301,38 +1206,79 @@ find_methods (struct symtab *symtab, char type,
/* Count of ObjC methods in this objfile should be constant. */
gdb_assert (*objc_csym == objfile_csym);
}
+}
+
+/* Uniquify a VEC of strings. */
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
+static void
+uniquify_strings (VEC (const_char_ptr) **strings)
+{
+ int ix;
+ const char *elem, *last = NULL;
+ int out;
+
+ qsort (VEC_address (const_char_ptr, *strings),
+ VEC_length (const_char_ptr, *strings),
+ sizeof (const_char_ptr),
+ compare_strings);
+ out = 0;
+ for (ix = 0; VEC_iterate (const_char_ptr, *strings, ix, elem); ++ix)
+ {
+ if (last == NULL || strcmp (last, elem) != 0)
+ {
+ /* Keep ELEM. */
+ VEC_replace (const_char_ptr, *strings, out, elem);
+ ++out;
+ }
+ last = elem;
+ }
+ VEC_truncate (const_char_ptr, *strings, out);
}
-char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+char *
+find_imps (char *method, VEC (const_char_ptr) **symbol_names)
{
char type = '\0';
char *class = NULL;
char *category = NULL;
char *selector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
- unsigned int ncsym = 0;
- unsigned int ncdebug = 0;
-
char *buf = NULL;
char *tmp = NULL;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
+ int selector_case = 0;
- if (nsym != NULL)
- *nsym = 0;
- if (ndebug != NULL)
- *ndebug = 0;
+ gdb_assert (symbol_names != NULL);
buf = (char *) alloca (strlen (method) + 1);
strcpy (buf, method);
@@ -1340,99 +1286,37 @@ char *find_imps (struct symtab *symtab, struct block *block,
if (tmp == NULL)
{
- struct symbol *sym = NULL;
- struct minimal_symbol *msym = NULL;
-
strcpy (buf, method);
tmp = parse_selector (buf, &selector);
if (tmp == NULL)
return NULL;
- sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
- if (sym != NULL)
- {
- if (syms)
- syms[csym] = sym;
- csym++;
- cdebug++;
- }
-
- if (sym == NULL)
- msym = lookup_minimal_symbol (selector, 0, 0);
-
- if (msym != NULL)
- {
- if (syms)
- syms[csym] = (struct symbol *)msym;
- csym++;
- }
+ selector_case = 1;
}
- if (syms != NULL)
- find_methods (symtab, type, class, category, selector,
- syms + csym, &ncsym, &ncdebug);
- else
- find_methods (symtab, type, class, category, selector,
- NULL, &ncsym, &ncdebug);
-
- /* If we didn't find any methods, just return. */
- if (ncsym == 0 && ncdebug == 0)
- return method;
+ find_methods (type, class, category, selector, symbol_names);
- /* Take debug symbols from the second batch of symbols and swap them
- * with debug symbols from the first batch. Repeat until either the
- * second section is out of debug symbols or the first section is
- * full of debug symbols. Either way we have all debug symbols
- * packed to the beginning of the buffer.
- */
-
- if (syms != NULL)
+ /* If we hit the "selector" case, and we found some methods, then
+ add the selector itself as a symbol, if it exists. */
+ if (selector_case && !VEC_empty (const_char_ptr, *symbol_names))
{
- while ((cdebug < csym) && (ncdebug > 0))
+ struct symbol *sym = lookup_symbol (selector, NULL, VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (sym));
+ else
{
- struct symbol *s = NULL;
- /* First non-debugging symbol. */
- unsigned int i = cdebug;
- /* Last of second batch of debug symbols. */
- unsigned int j = csym + ncdebug - 1;
-
- s = syms[j];
- syms[j] = syms[i];
- syms[i] = s;
-
- /* We've moved a symbol from the second debug section to the
- first one. */
- cdebug++;
- ncdebug--;
+ struct minimal_symbol *msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (msym));
}
}
- csym += ncsym;
- cdebug += ncdebug;
-
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
-
- if (syms == NULL)
- return method + (tmp - buf);
-
- if (csym > 1)
- {
- /* Sort debuggable symbols. */
- if (cdebug > 1)
- qsort (syms, cdebug, sizeof (struct minimal_symbol *),
- compare_classes);
-
- /* Sort minimal_symbols. */
- if ((csym - cdebug) > 1)
- qsort (&syms[cdebug], csym - cdebug,
- sizeof (struct minimal_symbol *), compare_classes);
- }
- /* Terminate the sym_arr list. */
- syms[csym] = 0;
+ uniquify_strings (symbol_names);
return method + (tmp - buf);
}
diff --git a/gdb/objc-lang.h b/gdb/objc-lang.h
index ee4cc29..351af7b 100644
--- a/gdb/objc-lang.h
+++ b/gdb/objc-lang.h
@@ -21,6 +21,8 @@
#if !defined(OBJC_LANG_H)
#define OBJC_LANG_H
+#include "cp-support.h" /* For VEC (const_char_ptr) */
+
struct stoken;
struct value;
@@ -39,15 +41,7 @@ extern char *objc_demangle (const char *mangled, int options);
extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
-extern char *parse_selector (char *method, char **selector);
-
-extern char *parse_method (char *method, char *type,
- char **class, char **category,
- char **selector);
-
-extern char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug);
+extern char *find_imps (char *method, VEC (const_char_ptr) **symbol_names);
extern struct value *value_nsstring (struct gdbarch *gdbarch,
char *ptr, int len);
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 1f3b3dc..2a1a879 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -125,13 +125,42 @@ require_partial_symbols (struct objfile *objfile, int verbose)
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p)
-/* Lookup the partial symbol table of a source file named NAME.
- *If* there is no '/' in the name, a match after a '/'
- in the psymtab filename will also work. */
+/* Helper function for partial_map_symtabs_matching_filename that
+ expands the symtabs and calls the iterator. */
-static struct partial_symtab *
-lookup_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path)
+static int
+partial_map_expand_apply (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ struct partial_symtab *pst,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded psymtabs. */
+ if (pst->readin)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ psymtab_to_symtab (pst);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
+static int
+partial_map_symtabs_matching_filename (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data)
{
struct partial_symtab *pst;
@@ -139,7 +168,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
/* If the user gave us an absolute path, try to find the file in
@@ -150,7 +181,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
if (pst->fullname != NULL
&& FILENAME_CMP (full_path, pst->fullname) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
@@ -165,7 +198,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
}
if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
}
@@ -176,29 +211,12 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path, pst,
+ callback, data))
+ return 1;
}
- return (NULL);
-}
-
-static int
-lookup_symtab_via_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
-{
- struct partial_symtab *ps;
-
- ps = lookup_partial_symtab (objfile, name, full_path, real_path);
- if (!ps)
- return 0;
-
- if (ps->readin)
- error (_("Internal: readin %s pst for `%s' found when no symtab found."),
- ps->filename, name);
-
- *result = PSYMTAB_TO_SYMTAB (ps);
- return 1;
+ return 0;
}
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
@@ -1288,7 +1306,7 @@ const struct quick_symbol_functions psym_functions =
objfile_has_psyms,
find_last_source_symtab_from_partial,
forget_cached_source_info_partial,
- lookup_symtab_via_partial_symtab,
+ partial_map_symtabs_matching_filename,
lookup_symbol_aux_psymtabs,
pre_expand_symtabs_matching_psymtabs,
print_psymtab_stats_for_objfile,
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 67696fd..8ab6631 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -843,7 +843,7 @@ DEF_VEC_O (type_equality_entry_d);
the same, 0 otherwise. Handles NULLs properly. */
static int
-compare_strings (const char *s, const char *t)
+compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
@@ -879,9 +879,10 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
- if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
+ TYPE_TAG_NAME (type2)))
return Py_NE;
- if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
@@ -904,7 +905,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
- if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_NAME (*field1),
+ FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
@@ -918,8 +920,8 @@ check_types_equal (struct type *type1, struct type *type2,
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
- if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
- FIELD_STATIC_PHYSNAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
+ FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 108e542..b898313 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -512,7 +512,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
{
copy = xstrdup (arg);
make_cleanup (xfree, copy);
- sals = decode_line_1 (©, 0, 0, 0, 0);
+ sals = decode_line_1 (©, 0, 0, 0);
make_cleanup (xfree, sals.sals);
}
else
diff --git a/gdb/skip.c b/gdb/skip.c
index 4bda3c4..29c7521 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -164,7 +164,7 @@ skip_function_command (char *arg, int from_tty)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&arg, 1, 0, 0, 0);
+ sals = decode_line_1 (&arg, 1, 0, 0);
}
if (decode_exception.reason < 0)
@@ -514,7 +514,7 @@ skip_re_set (void)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&func_name, 1, 0, 0, 0);
+ sals = decode_line_1 (&func_name, 1, 0, 0);
}
if (decode_exception.reason >= 0
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 888aa34..21efbdf 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -28,8 +28,6 @@
#include "gdb_string.h"
-DEF_VEC_I(CORE_ADDR);
-
/* Private data for each loaded library. */
struct lm_info
{
diff --git a/gdb/source.c b/gdb/source.c
index 6e29172..f68a855 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1408,12 +1408,14 @@ line_info (char *arg, int from_tty)
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
@@ -1427,11 +1429,15 @@ line_info (char *arg, int from_tty)
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
@@ -1497,7 +1503,7 @@ line_info (char *arg, int from_tty)
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */
diff --git a/gdb/stack.c b/gdb/stack.c
index 9136daa..48c1c27 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2444,20 +2444,25 @@ func_command (char *arg, int from_tty)
int i;
int level = 1;
struct function_bounds *func_bounds = NULL;
+ struct cleanup *cleanups;
if (arg != NULL)
return;
frame = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
+ cleanups = make_cleanup (xfree, sals.sals);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
+ make_cleanup (xfree, func_bounds);
for (i = 0; (i < sals.nelts && !found); i++)
{
- if (sals.sals[i].pc == 0
- || find_pc_partial_function (sals.sals[i].pc, NULL,
- &func_bounds[i].low,
- &func_bounds[i].high) == 0)
+ if (sals.sals[i].pspace != current_program_space)
+ func_bounds[i].low = func_bounds[i].high = 0;
+ else if (sals.sals[i].pc == 0
+ || find_pc_partial_function (sals.sals[i].pc, NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
{
func_bounds[i].low = func_bounds[i].high = 0;
}
@@ -2476,8 +2481,7 @@ func_command (char *arg, int from_tty)
}
while (!found && level == 0);
- if (func_bounds)
- xfree (func_bounds);
+ do_cleanups (cleanups);
if (!found)
printf_filtered (_("'%s' not within current stack frame.\n"), arg);
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 624df76..d45a226 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -152,22 +152,24 @@ struct quick_symbol_functions
/* Forget all cached full file names for OBJFILE. */
void (*forget_cached_source_info) (struct objfile *objfile);
- /* Look up the symbol table, in OBJFILE, of a source file named
- NAME. If there is no '/' in the name, a match after a '/' in the
- symbol table's file name will also work. FULL_PATH is the
- absolute file name, and REAL_PATH is the same, run through
- gdb_realpath.
-
- If no such symbol table can be found, returns 0.
-
- Otherwise, sets *RESULT to the symbol table and returns 1. This
- might return 1 and set *RESULT to NULL if the requested file is
- an include file that does not have a symtab of its own. */
- int (*lookup_symtab) (struct objfile *objfile,
- const char *name,
- const char *full_path,
- const char *real_path,
- struct symtab **result);
+ /* Expand and iterate over each "partial" symbol table in OBJFILE
+ where the source file is named NAME.
+
+ If there is no '/' in the name, a match after a '/' in the symbol
+ table's file name will also work. FULL_PATH is the absolute file
+ name, and REAL_PATH is the same, run through gdb_realpath.
+
+ If a match is found, the "partial" symbol table is expanded.
+ Then, this calls iterate_over_some_symtabs (or equivalent) over
+ all newly-created symbol tables, passing CALLBACK and DATA to it.
+ The result of this call is returned. */
+ int (*map_symtabs_matching_filename) (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data);
/* Check to see if the symbol is defined in a "partial" symbol table
of OBJFILE. KIND should be either GLOBAL_BLOCK or STATIC_BLOCK,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f881226..0d803aa 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -81,7 +81,7 @@ static void sources_info (char *, int);
static void output_source_filename (const char *, int *);
-static int find_line_common (struct linetable *, int, int *);
+static int find_line_common (struct linetable *, int, int *, int);
static struct symbol *lookup_symbol_aux (const char *name,
const struct block *block,
@@ -142,43 +142,36 @@ multiple_symbols_select_mode (void)
const struct block *block_found;
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
+/* Check for a symtab of a specific name by searching some symtabs.
+ This is a helper function for callbacks of iterate_over_symtabs.
-struct symtab *
-lookup_symtab (const char *name)
+ The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA
+ are identical to the `map_symtabs_matching_filename' method of
+ quick_symbol_functions.
+
+ FIRST and AFTER_LAST indicate the range of symtabs to search.
+ AFTER_LAST is one past the last symtab to search; NULL means to
+ search until the end of the list. */
+
+int
+iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last)
{
- int found;
struct symtab *s = NULL;
- struct objfile *objfile;
- char *real_path = NULL;
- char *full_path = NULL;
- struct cleanup *cleanup;
- cleanup = make_cleanup (null_cleanup, NULL);
-
- /* Here we are interested in canonicalizing an absolute path, not
- absolutizing a relative path. */
- if (IS_ABSOLUTE_PATH (name))
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- full_path = xfullpath (name);
- make_cleanup (xfree, full_path);
- real_path = gdb_realpath (name);
- make_cleanup (xfree, real_path);
- }
-
-got_symtab:
-
- /* First, search for an exact match. */
-
- ALL_SYMTABS (objfile, s)
- {
- if (FILENAME_CMP (name, s->filename) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
/* If the user gave us an absolute path, try to find the file in
this symtab and use its absolute path. */
@@ -189,8 +182,8 @@ got_symtab:
if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
{
- do_cleanups (cleanup);
- return s;
+ if (callback (s, data))
+ return 1;
}
}
@@ -204,62 +197,114 @@ got_symtab:
make_cleanup (xfree, rp);
if (FILENAME_CMP (real_path, rp) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
- }
+ }
/* Now, search for a matching tail (only if name doesn't have any dirs). */
if (lbasename (name) == name)
- ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- do_cleanups (cleanup);
- return s;
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
+ return 0;
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work.
+
+ Calls CALLBACK with each symtab that is found and with the supplied
+ DATA. If CALLBACK returns true, the search stops. */
+
+void
+iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data)
+{
+ struct symtab *s = NULL;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ if (iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, NULL))
+ {
+ do_cleanups (cleanups);
+ return;
+ }
+ }
+
/* Same search rules as above apply here, but now we look thru the
psymtabs. */
- found = 0;
ALL_OBJFILES (objfile)
{
if (objfile->sf
- && objfile->sf->qf->lookup_symtab (objfile, name, full_path, real_path,
- &s))
+ && objfile->sf->qf->map_symtabs_matching_filename (objfile,
+ name,
+ full_path,
+ real_path,
+ callback,
+ data))
{
- found = 1;
- break;
+ do_cleanups (cleanups);
+ return;
}
}
- if (s != NULL)
- {
- do_cleanups (cleanup);
- return s;
- }
- if (!found)
- {
- do_cleanups (cleanup);
- return NULL;
- }
+ do_cleanups (cleanups);
+}
+
+/* The callback function used by lookup_symtab. */
- /* At this point, we have located the psymtab for this file, but
- the conversion to a symtab has failed. This usually happens
- when we are looking up an include file. In this case,
- PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
- been created. So, we need to run through the symtabs again in
- order to find the file.
- XXX - This is a crock, and should be fixed inside of the
- symbol parsing routines. */
- goto got_symtab;
+static int
+lookup_symtab_callback (struct symtab *symtab, void *data)
+{
+ struct symtab **result_ptr = data;
+
+ *result_ptr = symtab;
+ return 1;
+}
+
+/* A wrapper for iterate_over_symtabs that returns the first matching
+ symtab, or NULL. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *result = NULL;
+
+ iterate_over_symtabs (name, lookup_symtab_callback, &result);
+ return result;
}
+
\f
/* Mangle a GDB method stub type. This actually reassembles the pieces of the
full method name, which consist of the class name (from T), the unadorned
@@ -994,33 +1039,16 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
return sym;
}
-/* Find the definition for a specified symbol name NAME
- in domain DOMAIN, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-/* This function has a bunch of loops in it and it would seem to be
- attractive to put in some QUIT's (though I'm not really sure
- whether it can run long enough to be really important). But there
- are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
- that there is C++ code below which can error(), but that probably
- doesn't affect these calls since they are looking for a known
- variable and thus can probably assume it will never hit the C++
- code). */
+/* Compute the demangled form of NAME as used by the various symbol
+ lookup functions. The result is stored in *RESULT_NAME. Returns a
+ cleanup which can be used to clean up the result. */
-struct symbol *
-lookup_symbol_in_language (const char *name, const struct block *block,
- const domain_enum domain, enum language lang,
- int *is_a_field_of_this)
+struct cleanup *
+demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
- struct symbol *returnval;
struct cleanup *cleanup = make_cleanup (null_cleanup, 0);
modified_name = name;
@@ -1067,6 +1095,38 @@ lookup_symbol_in_language (const char *name, const struct block *block,
}
}
+ *result_name = modified_name;
+ return cleanup;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
+
+struct symbol *
+lookup_symbol_in_language (const char *name, const struct block *block,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ const char *modified_name;
+ struct symbol *returnval;
+ struct cleanup *cleanup = demangle_for_lookup (name, lang, &modified_name);
+
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
@@ -1759,6 +1819,44 @@ lookup_block_symbol (const struct block *block, const char *name,
}
}
+/* Iterate over the symbols named NAME, matching DOMAIN, starting with
+ BLOCK.
+
+ For each symbol that matches, CALLBACK is called. The symbol and
+ DATA are passed to the callback.
+
+ If CALLBACK returns zero, the iteration ends. Otherwise, the
+ search continues. This function iterates upward through blocks.
+ When the outermost block has been finished, the function
+ returns. */
+
+void
+iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+ SYMBOL_DOMAIN (sym), domain))
+ {
+ if (!callback (sym, data))
+ return;
+ }
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+}
+
/* Find the symtab associated with PC and SECTION. Look through the
psymtabs and read in another symtab if necessary. */
@@ -2184,7 +2282,7 @@ find_line_symtab (struct symtab *symtab, int line,
/* First try looking it up in the given symtab. */
best_linetable = LINETABLE (symtab);
best_symtab = symtab;
- best_index = find_line_common (best_linetable, line, &exact);
+ best_index = find_line_common (best_linetable, line, &exact, 0);
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
@@ -2229,7 +2327,7 @@ find_line_symtab (struct symtab *symtab, int line,
&& FILENAME_CMP (symtab->fullname, s->fullname) != 0)
continue;
l = LINETABLE (s);
- ind = find_line_common (l, line, &exact);
+ ind = find_line_common (l, line, &exact, 0);
if (ind >= 0)
{
if (exact)
@@ -2260,6 +2358,86 @@ done:
return best_symtab;
}
+
+/* qsort comparison function for use by find_pcs_for_symtab_line. */
+
+static int
+compare_core_addrs (const void *a, const void *b)
+{
+ const CORE_ADDR *ca = a;
+ const CORE_ADDR *cb = b;
+
+ return (int) (ca - cb);
+}
+
+/* Given SYMTAB, return one PC per function in the symtab that exactly
+ matches LINE. Returns NULL if none matched. */
+
+VEC (CORE_ADDR) *
+find_pcs_for_symtab_line (struct symtab *symtab, int line)
+{
+ VEC (CORE_ADDR) *result = NULL;
+ int start = 0, ix;
+ struct symbol *previous_function = NULL;
+
+ /* First, collect all the PCs that are at this line. */
+ while (1)
+ {
+ int was_exact;
+ int idx;
+
+ idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+ if (idx < 0)
+ break;
+
+ if (!was_exact)
+ {
+ if (VEC_empty (CORE_ADDR, result))
+ {
+ /* We only found an inexact match. So, redo the search
+ for the found line. */
+ line = LINETABLE (symtab)->item[idx].line;
+ start = 0;
+ continue;
+ }
+ break;
+ }
+
+ VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+ start = idx + 1;
+ }
+
+ if (VEC_empty (CORE_ADDR, result))
+ return result;
+
+ qsort (VEC_address (CORE_ADDR, result), VEC_length (CORE_ADDR, result),
+ sizeof (CORE_ADDR), compare_core_addrs);
+
+ /* Remove all duplicate entries from the result. That is, each
+ function should only appear a single time. */
+ for (ix = 0; ix < VEC_length (CORE_ADDR, result); )
+ {
+ struct symbol *sym;
+ struct block *block;
+
+ block = block_for_pc (VEC_index (CORE_ADDR, result, ix));
+ sym = block ? block_containing_function (block) : NULL;
+
+ if (sym == NULL || sym == previous_function)
+ VEC_ordered_remove (CORE_ADDR, result, ix);
+ else
+ {
+ previous_function = sym;
+ ++ix;
+ }
+ }
+
+ if (VEC_length (CORE_ADDR, result) == 0)
+ VEC_free (CORE_ADDR, result);
+
+ return result;
+}
+
\f
/* Set the PC value for a given source file and line number and return true.
Returns zero for invalid line number (and sets the PC to 0).
@@ -2328,12 +2506,13 @@ find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr,
/* Given a line table and a line number, return the index into the line
table for the pc of the nearest line whose number is >= the specified one.
Return -1 if none is found. The value is >= 0 if it is an index.
+ START is the index at which to start searching the line table.
Set *EXACT_MATCH nonzero if the value returned is an exact match. */
static int
find_line_common (struct linetable *l, int lineno,
- int *exact_match)
+ int *exact_match, int start)
{
int i;
int len;
@@ -2353,7 +2532,7 @@ find_line_common (struct linetable *l, int lineno,
return -1;
len = l->nitems;
- for (i = 0; i < len; i++)
+ for (i = start; i < len; i++)
{
struct linetable_entry *item = &(l->item[i]);
@@ -4517,8 +4696,7 @@ decode_line_spec (char *string, int funfirstline)
cursal = get_current_source_symtab_and_line ();
sals = decode_line_1 (&string, funfirstline,
- cursal.symtab, cursal.line,
- NULL);
+ cursal.symtab, cursal.line);
if (*string)
error (_("Junk at end of line specification: %s"), string);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 90a6fe4..03f9a7a 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -22,6 +22,8 @@
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
+#include "vec.h"
+
/* Opaque declarations. */
struct ui_file;
struct frame_info;
@@ -1057,6 +1059,12 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern void iterate_over_minimal_symbols (struct objfile *objf,
+ const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data);
+
extern int in_gnu_ifunc_stub (CORE_ADDR pc);
/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
@@ -1307,4 +1315,30 @@ void fixup_section (struct general_symbol_info *ginfo,
struct objfile *lookup_objfile_from_block (const struct block *block);
+int iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last);
+
+void iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data);
+
+DEF_VEC_I (CORE_ADDR);
+
+VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line);
+
+void iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data);
+
+struct cleanup *demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name);
+
#endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 8b22324..d3c9cfc 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
- gdb.java gdb.mi gdb.modula2 gdb.multi \
+ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
$(SUBDIRS)
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 82206b3..fb70b3d 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4166,6 +4166,7 @@ do
"gdb.hp/gdb.aCC/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.aCC/Makefile" ;;
"gdb.hp/gdb.compat/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.compat/Makefile" ;;
"gdb.hp/gdb.defects/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.defects/Makefile" ;;
+ "gdb.linespec/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.linespec/Makefile" ;;
"gdb.mi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
"gdb.modula2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.multi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 8631442..121fd37 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -95,7 +95,7 @@ AC_OUTPUT([Makefile \
gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
- gdb.hp/gdb.defects/Makefile \
+ gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \
gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \
diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp
index 92fcc69..c5885ba 100644
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -540,8 +540,9 @@ gdb_test_multiple "catch exec" "$name" {
# Verify that GDB responds gracefully when asked to set a breakpoint
# on a nonexistent source line.
#
+gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in file .*" \
+ "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/list.exp b/gdb/testsuite/gdb.base/list.exp
index 5b9fe15..d4935ee 100644
--- a/gdb/testsuite/gdb.base/list.exp
+++ b/gdb/testsuite/gdb.base/list.exp
@@ -489,7 +489,7 @@ proc test_list_filename_and_function {} {
gdb_test "list foobar.c:main" "No source file named foobar.c.|Location not found" "list filename:function; nonexistant file"
- gdb_test "list list0.h:foobar" "Function \"foobar\" not defined.|Location not found" "list filename:function; nonexistant function"
+ gdb_test "list list0.h:foobar" "Function \"foobar\" not defined in \"list0.h\"." "list filename:function; nonexistant function"
}
diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp
index 1a9072d..bb0b914 100644
--- a/gdb/testsuite/gdb.base/sepdebug.exp
+++ b/gdb/testsuite/gdb.base/sepdebug.exp
@@ -337,7 +337,8 @@ gdb_test_multiple "catch exec" $name {
# on a nonexistent source line.
#
-gdb_test "break 999" "No line 999 in file .*" \
+gdb_test_no_output "set breakpoint pending off"
+gdb_test "break 999" "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index aa723c6..d402ebb 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -46,11 +46,6 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $binfile_lib
-if ![runto_main] then {
- fail "Can't run to main"
- return 0
-}
-
# Set a breakpoint in the binary.
gdb_test "br foo2" \
"Breakpoint.*file.*${testfile}\\.c.*" \
@@ -58,6 +53,11 @@ gdb_test "br foo2" \
delete_breakpoints
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
# Break in the library.
gdb_test "br foo" \
"Breakpoint.*file.*${libname}\\.c.*" \
@@ -67,9 +67,9 @@ gdb_test "continue" \
"Continuing.*" \
"continue"
-# This symbol is now looked up in the ELF library.
+# This symbol is now looked up in the ELF library and the binary.
gdb_test "br foo2" \
- "Breakpoint.*file.*${libname}\\.c.*" \
+ "Breakpoint.*: foo2. .2 locations..*" \
"foo2 in mdlib"
gdb_exit
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 6a99175..0438424 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -50,13 +50,13 @@ if ![runto_main] then {
# and a condition.
gdb_test "break 'Derived::Derived(int)'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
"set-breakpoint at ctor"
gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
gdb_test "break 'Derived::~Derived()'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
"set-breakpoint at dtor"
gdb_test "continue" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index d670b56..05b378c 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -62,7 +62,7 @@ set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
# Set a breakpoint with multiple locations.
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set breakpoint"
gdb_run_cmd
@@ -128,7 +128,7 @@ if { ![runto_main] } {
}
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 80c080b..933d690 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -52,7 +52,7 @@ set bp_location [gdb_get_line_number "set breakpoint here"]
# and a condition.
gdb_test "break $srcfile:$bp_location if i==1" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"initial condition: set breakpoint"
gdb_run_cmd
@@ -80,7 +80,7 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"separate condition: set breakpoint"
gdb_test_no_output "condition 1 i==1" \
@@ -177,7 +177,7 @@ if { ![runto_main] } {
}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/method2.exp b/gdb/testsuite/gdb.cp/method2.exp
index 2fa4169..29a387d 100644
--- a/gdb/testsuite/gdb.cp/method2.exp
+++ b/gdb/testsuite/gdb.cp/method2.exp
@@ -51,7 +51,7 @@ proc test_break { lang } {
"setting language $lang"
gdb_test_multiple "break A::method" "breaking in method ($lang)" {
- -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. A::method\\(A\\*\\) at .*\[\r\n\]*.3. A::method\\(int\\) at .*\[\r\n\]*\[\r\n\]*.4. A::method\\(\\) at .*\[\r\n\]*> $" {
+ -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. .*:A::method\\(A\\*\\)\[\r\n\]*.3. .*:A::method\\(int\\)\[\r\n\]*.4. .*:A::method\\(\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"breaking in method ($lang)"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index f5d4051..f5b41ab 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -130,18 +130,18 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} {
set menu_overload1arg "\\\[0\\\] cancel\r\n"
append menu_overload1arg "\\\[1\\\] all\r\n"
-append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n"
-append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n"
-append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n"
-append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n"
-append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n"
-append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n"
-append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n"
-append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n"
-append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n"
-append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n"
-append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n"
-append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n"
+append menu_overload1arg "\\\[2\\\] .*$srcfile:foo::overload1arg\\(double\\)\r\n"
+append menu_overload1arg "\\\[3\\\] .*$srcfile:foo::overload1arg\\(float\\)\r\n"
+append menu_overload1arg "\\\[4\\\] .*$srcfile:foo::overload1arg\\((unsigned long|long unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[5\\\] .*$srcfile:foo::overload1arg\\(long( int)?\\)\r\n"
+append menu_overload1arg "\\\[6\\\] .*$srcfile:foo::overload1arg\\((unsigned int|unsigned)\\)\r\n"
+append menu_overload1arg "\\\[7\\\] .*$srcfile:foo::overload1arg\\(int\\)\r\n"
+append menu_overload1arg "\\\[8\\\] .*$srcfile:foo::overload1arg\\((unsigned short|short unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[9\\\] .*$srcfile:foo::overload1arg\\(short( int)?\\)\r\n"
+append menu_overload1arg "\\\[10\\\] .*$srcfile:foo::overload1arg\\(unsigned char\\)\r\n"
+append menu_overload1arg "\\\[11\\\] .*$srcfile:foo::overload1arg\\(signed char\\)\r\n"
+append menu_overload1arg "\\\[12\\\] .*$srcfile:foo::overload1arg\\(char\\)\r\n"
+append menu_overload1arg "\\\[13\\\] .*$srcfile:foo::overload1arg\\((void|)\\)\r\n"
append menu_overload1arg "> $"
# Set multiple-symbols to "ask", to allow us to test the use
@@ -279,7 +279,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $decimal at $hex: file.*$srcfile, line 121.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 120.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 119.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 118.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 117.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 116.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 115.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 114.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 113.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 112.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 111.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 110.\r\nwarning: Multiple breakpoints were set.\r\nUse the .delete. command to delete unwanted breakpoints.\r\n$gdb_prompt $" {
+ -re "Breakpoint $decimal at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -306,18 +306,19 @@ gdb_expect {
gdb_test "info break" \
"Num Type\[\t \]+Disp Enb Address\[\t \]+What.*
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
+\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+<MULTIPLE>\[\t \]*\r
+\[0-9\]+.1\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
+\[0-9\]+.2\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
+\[0-9\]+.3\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
+\[0-9\]+.4\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
+\[0-9\]+.5\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
+\[0-9\]+.6\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
+\[0-9\]+.7\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
+\[0-9\]+.8\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
+\[0-9\]+.9\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
+\[0-9\]+.10\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
+\[0-9\]+.11\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
+\[0-9\]+.12\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
"breakpoint info (after setting on all)"
@@ -333,10 +334,10 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
send_gdb "continue\n"
gdb_expect {
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
pass "continue to bp overloaded : ${argtype}"
}
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
if $might_kfail {
kfail "gdb/1025" "continue to bp overloaded : ${argtype}"
} else {
@@ -352,17 +353,17 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
}
}
-continue_to_bp_overloaded 0 25 "(void|)" ""
-continue_to_bp_overloaded 1 24 "char" "arg=2 \\'\\\\002\\'"
-continue_to_bp_overloaded 1 23 "signed char" "arg=3 \\'\\\\003\\'"
-continue_to_bp_overloaded 1 22 "unsigned char" "arg=4 \\'\\\\004\\'"
-continue_to_bp_overloaded 1 21 "short" "arg=5"
-continue_to_bp_overloaded 1 20 "unsigned short" "arg=6"
-continue_to_bp_overloaded 0 19 "int" "arg=7"
-continue_to_bp_overloaded 0 18 "(unsigned|unsigned int)" "arg=8"
-continue_to_bp_overloaded 0 17 "long" "arg=9"
-continue_to_bp_overloaded 0 16 "unsigned long" "arg=10"
-continue_to_bp_overloaded 0 15 "float" "arg=100"
+continue_to_bp_overloaded 0 14 "(void|)" ""
+continue_to_bp_overloaded 1 14 "char" "arg=2 \\'\\\\002\\'"
+continue_to_bp_overloaded 1 14 "signed char" "arg=3 \\'\\\\003\\'"
+continue_to_bp_overloaded 1 14 "unsigned char" "arg=4 \\'\\\\004\\'"
+continue_to_bp_overloaded 1 14 "short" "arg=5"
+continue_to_bp_overloaded 1 14 "unsigned short" "arg=6"
+continue_to_bp_overloaded 0 14 "int" "arg=7"
+continue_to_bp_overloaded 0 14 "(unsigned|unsigned int)" "arg=8"
+continue_to_bp_overloaded 0 14 "long" "arg=9"
+continue_to_bp_overloaded 0 14 "unsigned long" "arg=10"
+continue_to_bp_overloaded 0 14 "float" "arg=100"
continue_to_bp_overloaded 1 14 "double" "arg=200"
# Test breaking on an overloaded function when multiple-symbols
@@ -375,7 +376,7 @@ gdb_test "break foo::foofunc" \
# is set to "all"
gdb_test_no_output "set multiple-symbols all"
gdb_test "break foo::foofunc" \
- "Breakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nBreakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nwarning: Multiple breakpoints were set\\.\r\nUse the \"delete\" command to delete unwanted breakpoints\\."
+ "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*"
# That's all, folks.
diff --git a/gdb/testsuite/gdb.cp/ovsrch.exp b/gdb/testsuite/gdb.cp/ovsrch.exp
index b509a25..3c3fd29 100644
--- a/gdb/testsuite/gdb.cp/ovsrch.exp
+++ b/gdb/testsuite/gdb.cp/ovsrch.exp
@@ -73,28 +73,28 @@ if {![runto_main]} {
}
# Break in A::stop_here and run tests.
-if {[gdb_breakpoint "stop_here"]} {
- pass "break stop_here"
+if {[gdb_breakpoint "A::stop_here"]} {
+ pass "break A::stop_here"
}
-if {[gdb_breakpoint "'stop_here'"]} {
- pass "break 'stop_here'"
+if {[gdb_breakpoint "'A::stop_here'"]} {
+ pass "break 'A::stop_here'"
}
gdb_continue_to_breakpoint "stop_here"
-test_class outer
+test_class A::outer
# Break in A::B::stop_here_too and run tests.
-if {[gdb_breakpoint "B::stop_here_too"]} {
- pass "break B::stop_here_too"
+if {[gdb_breakpoint "A::B::stop_here_too"]} {
+ pass "break A::B::stop_here_too"
}
-if {[gdb_breakpoint "'B::stop_here_too'"]} {
- pass "break 'B::stop_here_too'"
+if {[gdb_breakpoint "'A::B::stop_here_too'"]} {
+ pass "break 'A::B::stop_here_too'"
}
gdb_continue_to_breakpoint "stop_here_too"
-test_class inner
+test_class A::B::inner
gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.cp/re-set-overloaded.exp b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
index 2052552..bd5f3ba 100644
--- a/gdb/testsuite/gdb.cp/re-set-overloaded.exp
+++ b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
@@ -46,7 +46,6 @@ gdb_test_no_output {set variable $brk = $bpnum}
# runto or runto_main would call delete_breakpoints.
gdb_breakpoint "main"
gdb_run_cmd
-setup_kfail breakpoints/11657 *-*-*
gdb_test "" ".*" "start"
set test "breakpoint resolved"
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 6612b4a..9b1ae37 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -109,12 +109,7 @@ proc test_template_breakpoints {} {
global hp_aCC_compiler
gdb_test_multiple "break T5<int>::T5" "constructor breakpoint" {
- -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5<int>::T5\\(int\\) at .*\[\r\n\]*.3. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*\[\r\n\]*> $" {
- gdb_test "0" \
- "canceled" \
- "constructor breakpoint (obsolete format!)"
- }
- -re ".0. cancel\[\r\n\]*.1. all\[\r\n\]*.2. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*templates.cc:.*\[\r\n\]*.3. T5<int>::T5\\(int\\) at .*templates.cc:.*\[\r\n\]*> $" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\)\[\r\n\]*.3.*templates.cc:T5<int>::T5\\(int\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"constructor breakpoint"
@@ -153,7 +148,7 @@ proc test_template_breakpoints {} {
set bp_location [gdb_get_line_number \
"set breakpoint on a line with no real code"]
gdb_test "break ${testfile}.cc:${bp_location}" \
- "Breakpoint.*at.* file .*${testfile}.cc, line.*(2 locations).*" \
+ "Breakpoint.*at.*: .*${testfile}.cc:${bp_location}.*(2 locations).*" \
"breakpoint on a line with no real code"
delete_breakpoints
}
diff --git a/gdb/testsuite/gdb.linespec/Makefile.in b/gdb/testsuite/gdb.linespec/Makefile.in
new file mode 100644
index 0000000..2658a24
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/Makefile.in
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = lspec
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
new file mode 100644
index 0000000..882ccc9
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+
+
+
+
+
+int m(int x)
+{
+ return x + 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(int x)
+{
+ return x + 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
new file mode 100644
index 0000000..43917f8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+static int dupname(int y)
+{
+ label: return y;
+}
+
+int n(int y)
+{
+ return dupname(y) - 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(double x)
+{
+ return (int) x - 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
new file mode 100644
index 0000000..122a468
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -0,0 +1,106 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of ambiguous linespecs.
+
+set testfile linespec
+
+set exefile lspec
+set binfile ${objdir}/${subdir}/${exefile}
+
+set baseone base/one/thefile.cc
+set basetwo base/two/thefile.cc
+
+set hex {0x[0-9a-fA-F]+}
+
+if {[skip_cplus_tests]} {
+ unsupported linespec.exp
+ return
+}
+
+if {[prepare_for_testing ${testfile}.exp $exefile \
+ [list lspec.cc $baseone $basetwo] \
+ {debug nowarnings}]} {
+ return -1
+}
+
+gdb_test_no_output "set multiple-symbols all" \
+ "set multiple-symbols to all for linespec tests"
+
+set l1 [gdb_get_line_number "thefile breakpoint" $baseone]
+set l2 [gdb_get_line_number "thefile breakpoint" $basetwo]
+
+if {$l1 != $l2} {
+ error "somebody incompatibly modified the source files needed by linespec.exp"
+}
+
+gdb_test "break thefile.cc:$l1" \
+ "Breakpoint 1 at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
+ "multi-location break using file:line"
+
+# We'd like this to work, but it currently does not.
+# gdb_test "break one/thefile.cc:$l1"
+
+gdb_test "break dupname" \
+ "Breakpoint 2 at $hex: dupname. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name"
+
+gdb_test "break dupname:label" \
+ "Breakpoint 3 at $hex: dupname:label. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name and label"
+
+gdb_test_no_output "set breakpoint pending off" \
+ "disable pending breakpoints for linespec tests"
+
+# This is PR breakpoints/12856.
+gdb_test "break lspec.cc:nosuchfunction" \
+ "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
+ "set breakpoint on non-existent function"
+
+gdb_test "break NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
+ "set breakpoint at all instances of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at lspec.cc instance of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload(double)" \
+ "Function \"NameSpace::overload\\(double\\)\" not defined in \"lspec.cc\"." \
+ "set breakpoint at non-existent lspec.cc instance of NameSpace::overload"
+
+gdb_test "break NameSpace::overload()" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at specific instance of NameSpace::overload"
+
+#
+# Multi-inferior tests.
+#
+
+gdb_test "add-inferior" "Added inferior 2" \
+ "add inferior for linespec tests"
+
+gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch to inferior 2 for linespec tests"
+
+# Note that in particular this should not cause errors when re-setting
+# breakpoints.
+gdb_test "file $binfile" \
+ "Reading symbols from .*done." \
+ "set the new inferior file for linespec tests"
+
+gdb_test "break main" \
+ "Breakpoint \[0-9\]+ at $hex: main. .2 locations." \
+ "set breakpoint at main in both inferiors"
diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc
new file mode 100644
index 0000000..42e382f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.cc
@@ -0,0 +1,13 @@
+#include "lspec.h"
+
+static int dupname (int x) { label: return x; }
+
+int NameSpace::overload()
+{
+ return 23;
+}
+
+int main()
+{
+ return dupname(0) + m(0) + n(0);
+}
diff --git a/gdb/testsuite/gdb.linespec/lspec.h b/gdb/testsuite/gdb.linespec/lspec.h
new file mode 100644
index 0000000..e4bfc00
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.h
@@ -0,0 +1,9 @@
+extern int m(int x);
+extern int n(int y);
+
+namespace NameSpace {
+ int overload ();
+ int overload (int);
+ int overload (double);
+};
+
diff --git a/gdb/testsuite/gdb.objc/objcdecode.exp b/gdb/testsuite/gdb.objc/objcdecode.exp
index 720bfd8..e3916f6 100644
--- a/gdb/testsuite/gdb.objc/objcdecode.exp
+++ b/gdb/testsuite/gdb.objc/objcdecode.exp
@@ -52,17 +52,19 @@ proc do_objc_tests {} {
do_objc_tests
+gdb_test_no_output "set multiple-symbols ask"
+
#
# Break on multiply defined method (PR objc/1236)
#
set name "break on multiply defined method"
gdb_test_multiple "break multipleDef" $name \
{
- -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] -.Decode multipleDef. at .*\r\n\\\[3\\\] multipleDef at .*\r\n> $" {
+ -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] .*${srcfile}:-.Decode multipleDef.\r\n\\\[3\\\] .*${srcfile}:multipleDef\r\n> $" {
send_gdb "3\n"
exp_continue
}
- -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*\r\n$gdb_prompt $" { pass $name }
+ -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: .*\r\n$gdb_prompt $" { pass $name }
-re ".*$gdb_prompt $" { kfail "gdb/1236" $name }
}
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 679cc32..89a2e24 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -74,6 +74,7 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline2" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
+gdb_test_no_output "set breakpoint pending off"
gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
@@ -81,7 +82,6 @@ gdb_test "info trace" "No tracepoints.*" \
# 1.3 trace line in invalid source file
gdb_delete_tracepoints
-gdb_test_no_output "set breakpoint pending off"
gdb_test "trace NoSuChFiLe.c:1" "No source file named NoSuChFiLe.c." \
"1.3a: trace invalid source file"
gdb_test "info trace" "No tracepoints.*" \
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 4ca4ec2..be38d09 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2437,7 +2437,7 @@ scope_info (char *args, int from_tty)
error (_("requires an argument (function, "
"line or *addr) to define a scope"));
- sals = decode_line_1 (&args, 1, NULL, 0, NULL);
+ sals = decode_line_1 (&args, 1, NULL, 0);
if (sals.nelts == 0)
return; /* Presumably decode_line_1 has already warned. */
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 4c8658d..9b936e1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -455,29 +455,34 @@ tui_update_breakpoint_info (struct tui_win_info *win,
bp != (struct breakpoint *) NULL;
bp = bp->next)
{
+ struct bp_location *loc;
+
gdb_assert (line->line_or_addr.loa == LOA_LINE
|| line->line_or_addr.loa == LOA_ADDRESS);
- if ((win == TUI_SRC_WIN
- && bp->source_file
- && (filename_cmp (src->filename, bp->source_file) == 0)
- && line->line_or_addr.loa == LOA_LINE
- && bp->line_number == line->line_or_addr.u.line_no)
- || (win == TUI_DISASM_WIN
- && line->line_or_addr.loa == LOA_ADDRESS
- && bp->loc != NULL
- && bp->loc->address == line->line_or_addr.u.addr))
- {
- if (bp->enable_state == bp_disabled)
- mode |= TUI_BP_DISABLED;
- else
- mode |= TUI_BP_ENABLED;
- if (bp->hit_count)
- mode |= TUI_BP_HIT;
- if (bp->loc->cond)
- mode |= TUI_BP_CONDITIONAL;
- if (bp->type == bp_hardware_breakpoint)
- mode |= TUI_BP_HARDWARE;
- }
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && loc->source_file
+ && (filename_cmp (src->filename, loc->source_file) == 0)
+ && line->line_or_addr.loa == LOA_LINE
+ && loc->line_number == line->line_or_addr.u.line_no)
+ || (win == TUI_DISASM_WIN
+ && line->line_or_addr.loa == LOA_ADDRESS
+ && loc->address == line->line_or_addr.u.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->loc->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
}
if (line->has_break != mode)
{
diff --git a/gdb/utils.c b/gdb/utils.c
index 008baac..3bc3f94 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3693,6 +3693,17 @@ compare_positive_ints (const void *ap, const void *bp)
return * (int *) ap - * (int *) bp;
}
+/* String compare function for qsort. */
+
+int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+
+ return strcmp (*s1, *s2);
+}
+
#define AMBIGUOUS_MESS1 ".\nMatching formats:"
#define AMBIGUOUS_MESS2 \
".\nUse \"set gnutarget format-name\" to specify the format."
--
1.7.6.4
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 18:19 ` Tom Tromey
@ 2011-11-09 19:00 ` Joel Brobecker
2011-11-14 21:04 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Joel Brobecker @ 2011-11-09 19:00 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jerome Guitton, Jan Kratochvil, gdb-patches, Paul Hilfinger
> I think FILE:FUNCTION:LINE is a good form to provide to users, but it
> seems to me that it is incorrect to rewrite a user's "FUNCTION" linespec
> into this form. My reason is that it seems like it would do the wrong
> thing if the line number changes -- the linespec would stop working,
> rather than re-evaluate correctly. How do you deal with this problem?
Touche :-)! We do not deal with that issue. It hasn't been a real
problem so far, but it would be nice to have it solved nonetheless.
> Joel> The question is, can we use that same form for everyone? I thought
> Joel> you were going to do unconditional rewriting of the location string,
> Joel> but now I'm not so sure anymore...
>
> With my patch, only relative forms require rewriting. I think those are
> just "break LINE" and "break LABEL". The former is rewritten to
> FILE:LINE, and the latter to FUNCTION:LABEL.
OK, this makes sense.
> With multiple-symbols=ask, we also do filtering based on the "canonical
> form", which is different from the string used to re-evaluate.
>
> E.g., suppose you do "break something::method" and there are 5 methods.
> Suppose you have multiple-symbols=ask and you pick something::method(int).
> Then, we will have a breakpoint whose linespec is "something::method"
> but whose filter is "something::method(int)".
I wonder if we could start filtering based on function fully qualified
name, and profile (argument types) as well. In other words, if the user
does:
(gdb) break foo
and there are several functions named foo, then we'd have a filter
that says:
package1.foo(integer)
package2.instantiation.foo(float)
(etc). I think that might work, but I'll discuss it with Paul Hilfinger.
The only road-block I can foresee is the fact that I am unclear on
the resolution rules in Ada. I think they can get quite tricky, and
reproducing that in GDB might be a fair amount of work (if possible
at all). On the other hand, it would be nice to have that, because
we somewhat have something like that already for resolving inferior
function calls from GDB, but it's fairly primitive, and I think we
can call the wrong function sometimes (I just forgot the details).
Just curious: Are we planning on emitting a warning if re-evaluating
a breakpoint for which we no longer have a match for one of the entries
in the filter? This would happen if the user selected a function which,
after rebuilding the executable, no longer exists...
> I chose this somewhat odd design over the more straightforward
> rewriting of the linespec because there are canonical forms which are
> not yet suitable as input to linespec.
I actually like this design better. In fact, we don't even need the
filter to consist of strings. It could very well be something more
elaborate...
--
Joel
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 19:00 ` Joel Brobecker
@ 2011-11-14 21:04 ` Tom Tromey
2011-11-14 21:32 ` Jerome Guitton
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-14 21:04 UTC (permalink / raw)
To: Joel Brobecker
Cc: Jerome Guitton, Jan Kratochvil, gdb-patches, Paul Hilfinger
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
Tom> E.g., suppose you do "break something::method" and there are 5 methods.
Tom> Suppose you have multiple-symbols=ask and you pick something::method(int).
Tom> Then, we will have a breakpoint whose linespec is "something::method"
Tom> but whose filter is "something::method(int)".
Joel> I wonder if we could start filtering based on function fully qualified
Joel> name, and profile (argument types) as well. In other words, if the user
Joel> does:
Joel> (gdb) break foo
Joel> and there are several functions named foo, then we'd have a filter
Joel> that says:
Joel> package1.foo(integer)
Joel> package2.instantiation.foo(float)
Yeah, this is actually what happens in multiple-symbols=ask mode: we
present the canonical forms to the user, and record as the filter the
one that he chooses.
An implication of this is that we don't discriminate more finely than
what can be encoded in the canonical form. So, for example, one cannot
set a symbolic (as opposed to by-address) breakpoint at a single point
of inlining -- because the canonical form for the inlined function will
be identical across inlined instances.
I don't know if that description makes any sense outside my head :)
Joel> The only road-block I can foresee is the fact that I am unclear on
Joel> the resolution rules in Ada. I think they can get quite tricky, and
Joel> reproducing that in GDB might be a fair amount of work (if possible
Joel> at all). On the other hand, it would be nice to have that, because
Joel> we somewhat have something like that already for resolving inferior
Joel> function calls from GDB, but it's fairly primitive, and I think we
Joel> can call the wrong function sometimes (I just forgot the details).
Yeah, the issue in this sub-thread is whether or not to perform name
lookup.
My view is that if the name lookup is context-dependent, then we should
not do it. E.g., in the C++ example, having "break m" search namespaces
would either require us to (1) rewrite the linespec from "m" to
something else for purposes of re-evaluation, or (2) store the context.
I tend to think neither one is very good and that we slipped into doing
this in the first place by accident, not design.
Joel> Just curious: Are we planning on emitting a warning if re-evaluating
Joel> a breakpoint for which we no longer have a match for one of the entries
Joel> in the filter? This would happen if the user selected a function which,
Joel> after rebuilding the executable, no longer exists...
It just silently stays around. I believe "info break" will show it as
pending.
Joel> I actually like this design better. In fact, we don't even need the
Joel> filter to consist of strings. It could very well be something more
Joel> elaborate...
Yeah; we discussed that at some point, but I didn't seem to need it.
It is still available as a future change though.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-09 18:37 ` Tom Tromey
@ 2011-11-14 21:11 ` Tom Tromey
2011-11-15 16:30 ` Tom Tromey
` (5 more replies)
0 siblings, 6 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-14 21:11 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> Here is a refresh of this patch. This fixes the regressions noted by
Tom> Jan, but also changes ovsrch.exp not to assume that namespace lookups
Tom> are done.
Here is the final revision.
I plan to commit this sometime this week, barring objections or
comments; after the doc patch (forthcoming) is approved.
This version fixes a buglet noticed by Jan (bad cleanup use).
I realized there are a couple of concrete benefits to this patch that
might not be immediately apparent, so I thought I'd write about them
here.
First, when debugging gdb itself, "break parse_number" will now always
break where you wanted -- this case was actually a partial motivation
for this change; in the past this set a breakpoint in p-exp.y, which was
not the file I happened to be looking at. Now it sets a breakpoint at
all 7 instances.
Second, it makes multi-inferior pending breakpoints very easy.
Previously, I found them to be tricky to set up. For example, here is
setting a breakpoint in cc1 and then running gcc:
(gdb) b _cpp_lex_token
Function "_cpp_lex_token" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (_cpp_lex_token) pending.
(gdb) r
Starting program: /home/tromey/Space/Trunk/install/bin/gcc --syntax-only /tmp/q.c
[New process 10757]
process 10757 is executing new program: /home/tromey/Space/Trunk/install/libexec/gcc/x86_64-unknown-linux-gnu/4.7.0/cc1
Breakpoint 1, _cpp_lex_token (pfile=0x1a21d40) at ../../trunk/libcpp/lex.c:1801
Tom
2011-11-10 Tom Tromey <tromey@redhat.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:
* 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.
* 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.
* 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.
(compare_core_addrs, find_pcs_for_symtab_line): New functions.
(find_line_common): Add 'start' argument.
(decode_line_spec): Update.
* 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.
* source.c (line_info): Set pspace on sal. Check program space in
the loop.
* 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 (struct linespec_sals): New type.
(struct linespec_result) <canonical>: Remove.
<pre_expanded, addr_string, sals>: New fields.
(destroy_linespec_result, make_cleanup_destroy_linespec_result)
(decode_line_list, 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, decode_line_list): 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. Fall back on
decode_variable.
(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.
* 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. 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.
(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.
* block.h (block_containing_function): Declare.
* block.c (block_containing_function): New function.
* skip.c (skip_function_command): Update.
(skip_re_set): Update.
2011-10-28 Tom Tromey <tromey@redhat.com>
* 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/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.
From f795e0cb411f367e120e330e004973c6a3456546 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 27 Oct 2011 09:26:30 -0600
Subject: [PATCH 3/4] the rewrite
---
gdb/ChangeLog | 150 ++
gdb/block.c | 14 +
gdb/block.h | 2 +
gdb/breakpoint.c | 546 +++----
gdb/breakpoint.h | 21 +-
gdb/cli/cli-cmds.c | 103 +-
gdb/defs.h | 1 +
gdb/dwarf2loc.c | 3 -
gdb/dwarf2read.c | 60 +-
gdb/linespec.c | 2489 +++++++++++++++---------
gdb/linespec.h | 105 +-
gdb/minsyms.c | 40 +
gdb/objc-lang.c | 288 +--
gdb/objc-lang.h | 12 +-
gdb/psymtab.c | 80 +-
gdb/python/py-type.c | 14 +-
gdb/python/python.c | 2 +-
gdb/skip.c | 4 +-
gdb/solib-target.c | 2 -
gdb/source.c | 8 +-
gdb/stack.c | 16 +-
gdb/symfile.h | 34 +-
gdb/symtab.c | 372 +++-
gdb/symtab.h | 34 +
gdb/testsuite/ChangeLog | 32 +
gdb/testsuite/Makefile.in | 2 +-
gdb/testsuite/configure | 3 +-
gdb/testsuite/configure.ac | 2 +-
gdb/testsuite/gdb.base/break.exp | 3 +-
gdb/testsuite/gdb.base/list.exp | 2 +-
gdb/testsuite/gdb.base/sepdebug.exp | 3 +-
gdb/testsuite/gdb.base/solib-symbol.exp | 14 +-
gdb/testsuite/gdb.cp/mb-ctor.exp | 4 +-
gdb/testsuite/gdb.cp/mb-inline.exp | 4 +-
gdb/testsuite/gdb.cp/mb-templates.exp | 6 +-
gdb/testsuite/gdb.cp/method2.exp | 2 +-
gdb/testsuite/gdb.cp/ovldbreak.exp | 79 +-
gdb/testsuite/gdb.cp/ovsrch.exp | 20 +-
gdb/testsuite/gdb.cp/re-set-overloaded.exp | 1 -
gdb/testsuite/gdb.cp/templates.exp | 9 +-
gdb/testsuite/gdb.linespec/Makefile.in | 14 +
gdb/testsuite/gdb.linespec/base/one/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/base/two/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/linespec.exp | 106 +
gdb/testsuite/gdb.linespec/lspec.cc | 13 +
gdb/testsuite/gdb.linespec/lspec.h | 9 +
gdb/testsuite/gdb.objc/objcdecode.exp | 6 +-
gdb/testsuite/gdb.trace/tracecmd.exp | 2 +-
gdb/tracepoint.c | 2 +-
gdb/tui/tui-winsource.c | 47 +-
gdb/utils.c | 11 +
51 files changed, 3051 insertions(+), 1783 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/Makefile.in
create mode 100644 gdb/testsuite/gdb.linespec/base/one/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/base/two/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/linespec.exp
create mode 100644 gdb/testsuite/gdb.linespec/lspec.cc
create mode 100644 gdb/testsuite/gdb.linespec/lspec.h
diff --git a/gdb/block.c b/gdb/block.c
index c165bc2..1fa3688 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -82,6 +82,20 @@ block_linkage_function (const struct block *bl)
return BLOCK_FUNCTION (bl);
}
+/* Return the symbol for the function which contains a specified
+ block, described by a struct block BL. The return value will be
+ the closest enclosing function, which might be an inline
+ function. */
+
+struct symbol *
+block_containing_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
/* Return one if BL represents an inlined function. */
int
diff --git a/gdb/block.h b/gdb/block.h
index 1742f24..63b18a6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -131,6 +131,8 @@ struct blockvector
extern struct symbol *block_linkage_function (const struct block *);
+extern struct symbol *block_containing_function (const struct block *);
+
extern int block_inlined_p (const struct block *block);
extern int contained_in (const struct block *, const struct block *);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 01ca912..4402ed7 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4549,7 +4549,7 @@ print_breakpoint_location (struct breakpoint *b,
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (b->source_file && loc)
+ else if (loc && loc->source_file)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
@@ -4562,7 +4562,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_field_string (uiout, "file", loc->source_file);
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
@@ -4574,7 +4574,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_field_string (uiout, "fullname", fullname);
}
- ui_out_field_int (uiout, "line", b->line_number);
+ ui_out_field_int (uiout, "line", loc->line_number);
}
else if (loc)
{
@@ -5798,12 +5798,10 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sal.symtab->filename);
+ if (sal.symtab != NULL)
+ b->loc->source_file = xstrdup (sal.symtab->filename);
b->loc->section = sal.section;
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
set_breakpoint_location_function (b->loc,
sal.explicit_pc || sal.explicit_line);
@@ -7000,12 +6998,10 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
- if (orig->source_file == NULL)
- copy->source_file = NULL;
- else
- copy->source_file = xstrdup (orig->source_file);
+ if (orig->loc->source_file != NULL)
+ copy->loc->source_file = xstrdup (orig->loc->source_file);
- copy->line_number = orig->line_number;
+ copy->loc->line_number = orig->loc->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
@@ -7078,6 +7074,10 @@ add_location_to_breakpoint (struct breakpoint *b,
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
+ if (sal->symtab != NULL)
+ loc->source_file = xstrdup (sal->symtab->filename);
+ loc->line_number = sal->line;
+
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
return loc;
@@ -7134,7 +7134,7 @@ bp_loc_is_permanent (struct bp_location *loc)
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7248,12 +7248,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
me. */
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->filter = filter;
}
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7276,7 +7277,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- cond_string,
+ filter, cond_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
@@ -7286,138 +7287,6 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
install_breakpoint (internal, b);
}
-/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
- elements to fill the void space. */
-static void
-remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
-{
- int i = index_to_remove+1;
- int last_index = sal->nelts-1;
-
- for (;i <= last_index; ++i)
- sal->sals[i-1] = sal->sals[i];
-
- --(sal->nelts);
-}
-
-/* If appropriate, obtains all sals that correspond to the same file
- and line as SAL, in all program spaces. Users debugging with IDEs,
- will want to set a breakpoint at foo.c:line, and not really care
- about program spaces. This is done only if SAL does not have
- explicit PC and has line and file information. If we got just a
- single expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out all sals for
- which the name of enclosing function is different from SAL. This
- makes sure that if we have breakpoint originally set in template
- instantiation, say foo<int>(), we won't expand SAL to locations at
- the same line in all existing instantiations of 'foo'. */
-
-static struct symtabs_and_lines
-expand_line_sal_maybe (struct symtab_and_line sal)
-{
- struct symtabs_and_lines expanded;
- CORE_ADDR original_pc = sal.pc;
- char *original_function = NULL;
- int found;
- int i;
- struct cleanup *old_chain;
-
- /* If we have explicit pc, don't expand.
- If we have no line number, we can't expand. */
- if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
- {
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sal;
- return expanded;
- }
-
- sal.pc = 0;
-
- old_chain = save_current_space_and_thread ();
-
- switch_to_program_space_and_thread (sal.pspace);
-
- find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
- /* Note that expand_line_sal visits *all* program spaces. */
- expanded = expand_line_sal (sal);
-
- if (expanded.nelts == 1)
- {
- /* We had one sal, we got one sal. Return that sal, adjusting it
- past the function prologue if necessary. */
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- skip_prologue_sal (&expanded.sals[0]);
- do_cleanups (old_chain);
- return expanded;
- }
-
- if (!sal.explicit_line)
- {
- CORE_ADDR func_addr, func_end;
- for (i = 0; i < expanded.nelts; ++i)
- {
- CORE_ADDR pc = expanded.sals[i].pc;
- char *this_function;
-
- /* We need to switch threads as well since we're about to
- read memory. */
- switch_to_program_space_and_thread (expanded.sals[i].pspace);
-
- if (find_pc_partial_function (pc, &this_function,
- &func_addr, &func_end))
- {
- if (this_function
- && strcmp (this_function, original_function) != 0)
- {
- remove_sal (&expanded, i);
- --i;
- }
- }
- }
- }
-
- /* Skip the function prologue if necessary. */
- for (i = 0; i < expanded.nelts; ++i)
- skip_prologue_sal (&expanded.sals[i]);
-
- do_cleanups (old_chain);
-
- if (expanded.nelts <= 1)
- {
- /* This is an ugly workaround. If we get zero expanded sals
- then something is really wrong. Fix that by returning the
- original sal. */
-
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- return expanded;
- }
-
- if (original_pc)
- {
- found = 0;
- for (i = 0; i < expanded.nelts; ++i)
- if (expanded.sals[i].pc == original_pc)
- {
- found = 1;
- break;
- }
- gdb_assert (found);
- }
-
- return expanded;
-}
-
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
@@ -7435,7 +7304,6 @@ expand_line_sal_maybe (struct symtab_and_line sal)
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals,
struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
@@ -7444,17 +7312,30 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
int enabled, int internal)
{
int i;
+ struct linespec_sals *lsal;
- for (i = 0; i < sals.nelts; ++i)
+ if (canonical->pre_expanded)
+ gdb_assert (VEC_length (linespec_sals, canonical->sals) == 1);
+
+ for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
{
- struct symtabs_and_lines expanded =
- expand_line_sal_maybe (sals.sals[i]);
+ /* Note that 'addr_string' can be NULL in the case of a plain
+ 'break', without arguments. */
+ char *addr_string = (canonical->addr_string
+ ? xstrdup (canonical->addr_string)
+ : NULL);
+ char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
+ struct cleanup *inner = make_cleanup (xfree, addr_string);
- create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
+ make_cleanup (xfree, filter_string);
+ create_breakpoint_sal (gdbarch, lsal->sals,
+ addr_string,
+ filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
canonical->special_display);
+ discard_cleanups (inner);
}
}
@@ -7468,7 +7349,6 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (char **address,
- struct symtabs_and_lines *sals,
struct linespec_result *canonical)
{
char *addr_start = *address;
@@ -7482,10 +7362,11 @@ parse_breakpoint_sals (char **address,
address. */
if (last_displayed_sal_is_valid ())
{
+ struct linespec_sals lsal;
struct symtab_and_line sal;
init_sal (&sal); /* Initialize to zeroes. */
- sals->sals = (struct symtab_and_line *)
+ lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
/* Set sal's pspace, pc, symtab, and line to the values
@@ -7500,8 +7381,11 @@ parse_breakpoint_sals (char **address,
instances with the same symtab and line. */
sal.explicit_pc = 1;
- sals->sals[0] = sal;
- sals->nelts = 1;
+ lsal.sals.sals[0] = sal;
+ lsal.sals.nelts = 1;
+ lsal.canonical = NULL;
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
else
error (_("No default breakpoint address now."));
@@ -7511,40 +7395,15 @@ parse_breakpoint_sals (char **address,
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving the last displayed codepoint pointers
- alone.
-
- ObjC: However, don't match an Objective-C method name which
- may have a '+' or '-' succeeded by a '[' */
-
- struct symtab_and_line cursal = get_current_source_symtab_and_line ();
-
- if (last_displayed_sal_is_valid ()
- && (!cursal.symtab
- || ((strchr ("+-", (*address)[0]) != NULL)
- && ((*address)[1] != '['))))
- *sals = decode_line_1 (address, 1,
- get_last_displayed_symtab (),
- get_last_displayed_line (),
- canonical);
+ time while leaving default_breakpoint_* alone. */
+ if (last_displayed_sal_is_valid ())
+ decode_line_full (address, 1,
+ get_last_displayed_symtab (),
+ get_last_displayed_line (),
+ canonical, NULL, NULL);
else
- *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- canonical);
- }
- /* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && canonical->canonical == NULL)
- canonical->canonical = xcalloc (sals->nelts, sizeof (char *));
- if (addr_start != (*address))
- {
- int i;
-
- for (i = 0; i < sals->nelts; i++)
- {
- /* Add the string if not present. */
- if (canonical->canonical[i] == NULL)
- canonical->canonical[i] = savestring (addr_start,
- (*address) - addr_start);
- }
+ decode_line_full (address, 1, (struct symtab *) NULL, 0,
+ canonical, NULL, NULL);
}
}
@@ -7579,15 +7438,20 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
for (i = 0; i < sals->nelts; i++)
{
+ struct gdbarch *sarch;
+
sal = &sals->sals[i];
- rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ sarch = get_sal_arch (*sal);
+ if (sarch == NULL)
+ sarch = gdbarch;
+ rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
NULL, &msg);
old_chain = make_cleanup (xfree, msg);
if (!rslt)
error (_("May not have a fast tracepoint at 0x%s%s"),
- paddress (gdbarch, sal->pc), (msg ? msg : ""));
+ paddress (sarch, sal->pc), (msg ? msg : ""));
do_cleanups (old_chain);
}
@@ -7729,8 +7593,6 @@ create_breakpoint (struct gdbarch *gdbarch,
int from_tty, int enabled, int internal)
{
volatile struct gdb_exception e;
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
char *copy_arg;
char *addr_start = arg;
struct linespec_result canonical;
@@ -7743,26 +7605,26 @@ create_breakpoint (struct gdbarch *gdbarch,
gdb_assert (ops != NULL);
- sals.sals = NULL;
- sals.nelts = 0;
init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
int i;
+ struct linespec_sals lsal;
- sals = decode_static_tracepoint_spec (&arg);
+ lsal.sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
- for (i = 0; i < sals.nelts; i++)
- canonical.canonical[i] = xstrdup (copy_arg);
+
+ lsal.canonical = xstrdup (copy_arg);
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+
goto done;
}
TRY_CATCH (e, RETURN_MASK_ALL)
{
- parse_breakpoint_sals (&arg, &sals, &canonical);
+ parse_breakpoint_sals (&arg, &canonical);
}
/* If caller is interested in rc value from parse, set value. */
@@ -7794,35 +7656,31 @@ create_breakpoint (struct gdbarch *gdbarch,
a pending breakpoint and selected yes, or pending
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
- copy_arg = xstrdup (addr_start);
- canonical.canonical = ©_arg;
- sals.nelts = 1;
- sals.sals = &pending_sal;
- pending_sal.pc = 0;
- pending = 1;
+ {
+ struct linespec_sals lsal;
+
+ copy_arg = xstrdup (addr_start);
+ lsal.canonical = xstrdup (copy_arg);
+ lsal.sals.nelts = 1;
+ lsal.sals.sals = XNEW (struct symtab_and_line);
+ init_sal (&lsal.sals.sals[0]);
+ pending = 1;
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+ }
break;
default:
throw_exception (e);
}
break;
default:
- if (!sals.nelts)
+ if (VEC_empty (linespec_sals, canonical.sals))
return 0;
}
done:
/* Create a chain of things that always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- if (!pending)
- {
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the canonical array but not its contents. */
- make_cleanup (xfree, canonical.canonical);
- }
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
@@ -7830,28 +7688,36 @@ create_breakpoint (struct gdbarch *gdbarch,
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the canonical for cleanup. These go on
- the bkpt_chain and only occur if the breakpoint create fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (canonical.canonical[i] != NULL)
- make_cleanup (xfree, canonical.canonical[i]);
- }
-
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ breakpoint_sals_to_pc (&iter->sals);
+ }
/* Fast tracepoints may have additional restrictions on location. */
if (type_wanted == bp_fast_tracepoint)
- check_fast_tracepoint_sals (gdbarch, &sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ check_fast_tracepoint_sals (gdbarch, &iter->sals);
+ }
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
if (!pending)
{
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+
if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
@@ -7860,7 +7726,7 @@ create_breakpoint (struct gdbarch *gdbarch,
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
&thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
@@ -7882,24 +7748,26 @@ create_breakpoint (struct gdbarch *gdbarch,
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (canonical.canonical[0]))
+ && is_marker_spec (lsal->canonical))
{
int i;
- for (i = 0; i < sals.nelts; ++i)
+ for (i = 0; i < lsal->sals.nelts; ++i)
{
struct symtabs_and_lines expanded;
struct tracepoint *tp;
struct cleanup *old_chain;
+ char *addr_string;
expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sals.sals[i];
- old_chain = make_cleanup (xfree, expanded.sals);
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical.addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
- canonical.canonical[i],
+ addr_string, NULL,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
@@ -7915,11 +7783,11 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, &tp->base);
- do_cleanups (old_chain);
+ discard_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
+ create_breakpoints_sal (gdbarch, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
@@ -7934,7 +7802,7 @@ create_breakpoint (struct gdbarch *gdbarch,
b = set_raw_breakpoint_without_location (gdbarch, type_wanted, ops);
set_breakpoint_number (internal, b);
b->thread = -1;
- b->addr_string = canonical.canonical[0];
+ b->addr_string = copy_arg;
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
@@ -7951,7 +7819,7 @@ create_breakpoint (struct gdbarch *gdbarch,
observer_notify_breakpoint_created (b);
}
- if (sals.nelts > 1)
+ if (VEC_length (linespec_sals, canonical.sals) > 1)
{
warning (_("Multiple breakpoints were set.\nUse the "
"\"delete\" command to delete unwanted breakpoints."));
@@ -8332,8 +8200,8 @@ break_range_command (char *arg, int from_tty)
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
- struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
+ struct linespec_sals *lsal_start, *lsal_end;
/* We don't support software ranged breakpoints. */
if (target_ranged_break_num_registers () < 0)
@@ -8346,71 +8214,58 @@ break_range_command (char *arg, int from_tty)
if (can_use_bp < 0)
error (_("Hardware breakpoints used exceeds limit."));
+ arg = skip_spaces (arg);
if (arg == NULL || arg[0] == '\0')
error(_("No address range specified."));
- sals_start.sals = NULL;
- sals_start.nelts = 0;
init_linespec_result (&canonical_start);
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ parse_breakpoint_sals (&arg, &canonical_start);
- parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
-
- sal_start = sals_start.sals[0];
- addr_string_start = canonical_start.canonical[0];
- cleanup_bkpt = make_cleanup (xfree, addr_string_start);
- xfree (sals_start.sals);
- xfree (canonical_start.canonical);
+ cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
if (arg[0] != ',')
error (_("Too few arguments."));
- else if (sals_start.nelts == 0)
+ else if (VEC_empty (linespec_sals, canonical_start.sals))
error (_("Could not find location of the beginning of the range."));
- else if (sals_start.nelts != 1)
+
+ lsal_start = VEC_index (linespec_sals, canonical_start.sals, 0);
+
+ if (VEC_length (linespec_sals, canonical_start.sals) > 1
+ || lsal_start->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_start);
+ sal_start = lsal_start->sals.sals[0];
+ addr_string_start = lsal_start->canonical;
arg++; /* Skip the comma. */
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ arg = skip_spaces (arg);
/* Parse the end location. */
- sals_end.sals = NULL;
- sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
- /* We call decode_line_1 directly here instead of using
+ /* We call decode_line_full directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
- sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
- &canonical_end);
-
- /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
- if (canonical_end.canonical == NULL)
- canonical_end.canonical = xcalloc (1, sizeof (char *));
- /* Add the string if not present. */
- if (arg_start != arg && canonical_end.canonical[0] == NULL)
- canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
-
- sal_end = sals_end.sals[0];
- addr_string_end = canonical_end.canonical[0];
- make_cleanup (xfree, addr_string_end);
- xfree (sals_end.sals);
- xfree (canonical_end.canonical);
-
- if (sals_end.nelts == 0)
+ decode_line_full (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end, NULL, NULL);
+
+ make_cleanup_destroy_linespec_result (&canonical_end);
+
+ if (VEC_empty (linespec_sals, canonical_end.sals))
error (_("Could not find location of the end of the range."));
- else if (sals_end.nelts != 1)
+
+ lsal_end = VEC_index (linespec_sals, canonical_end.sals, 0);
+ if (VEC_length (linespec_sals, canonical_end.sals) > 1
+ || lsal_end->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_end);
+ sal_end = lsal_end->sals.sals[0];
+ addr_string_end = lsal_end->canonical;
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
@@ -8437,11 +8292,11 @@ break_range_command (char *arg, int from_tty)
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
- b->addr_string = addr_string_start;
- b->addr_string_range_end = addr_string_end;
+ b->addr_string = xstrdup (addr_string_start);
+ b->addr_string_range_end = xstrdup (addr_string_end);
b->loc->length = length;
- discard_cleanups (cleanup_bkpt);
+ do_cleanups (cleanup_bkpt);
mention (b);
observer_notify_breakpoint_created (b);
@@ -9550,10 +9405,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&arg, 1,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
@@ -10136,18 +9990,21 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
- && (loc->pspace == sal.pspace)
- && (loc->address == sal.pc)
- && (!section_is_overlay (loc->section)
- || loc->section == sal.section);
- int line_match = ((default_match || (0 == sal.pc))
- && b->source_file != NULL
+ /* If the user specified file:line, don't allow a PC
+ match. This matches historical gdb behavior. */
+ int pc_match = (!sal.explicit_line
+ && sal.pc
+ && (loc->pspace == sal.pspace)
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section));
+ int line_match = ((default_match || sal.explicit_line)
+ && loc->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && filename_cmp (b->source_file,
+ && filename_cmp (loc->source_file,
sal.symtab->filename) == 0
- && b->line_number == sal.line);
+ && loc->line_number == sal.line);
if (pc_match || line_match)
{
match = 1;
@@ -10683,15 +10540,25 @@ say_where (struct breakpoint *b)
}
else
{
- if (opts.addressprint || b->source_file == NULL)
+ if (opts.addressprint || b->loc->source_file == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
if (b->loc->next)
{
@@ -10711,6 +10578,7 @@ bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
xfree (self->function_name);
+ xfree (self->source_file);
}
static const struct bp_location_ops bp_location_ops =
@@ -10727,8 +10595,8 @@ base_breakpoint_dtor (struct breakpoint *self)
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
xfree (self->addr_string);
+ xfree (self->filter);
xfree (self->addr_string_range_end);
- xfree (self->source_file);
}
static struct bp_location *
@@ -11559,17 +11427,18 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
ui_out_field_int (uiout, "line", sal.line);
ui_out_text (uiout, "\n");
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
- xfree (b->source_file);
+ xfree (b->loc->source_file);
if (sym)
- b->source_file = xstrdup (sal.symtab->filename);
+ b->loc->source_file = xstrdup (sal.symtab->filename);
else
- b->source_file = NULL;
+ b->loc->source_file = NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal.symtab->filename, b->line_number);
+ sal.symtab->filename,
+ b->loc->line_number);
/* Might be nice to check if function changed, and warn if
so. */
@@ -11619,8 +11488,17 @@ update_breakpoint_locations (struct breakpoint *b,
int i;
struct bp_location *existing_locations = b->loc;
- /* Ranged breakpoints have only one start location and one end location. */
- gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+ if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
+ {
+ /* Ranged breakpoints have only one start location and one end
+ location. */
+ b->enable_state = bp_disabled;
+ update_global_location_list (1);
+ printf_unfiltered (_("Could not reset ranged breakpoint %d: "
+ "multiple locations found\n"),
+ b->number);
+ return;
+ }
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
@@ -11635,8 +11513,11 @@ update_breakpoint_locations (struct breakpoint *b,
for (i = 0; i < sals.nelts; ++i)
{
- struct bp_location *new_loc =
- add_location_to_breakpoint (b, &(sals.sals[i]));
+ struct bp_location *new_loc;
+
+ switch_to_program_space_and_thread (sals.sals[i].pspace);
+
+ new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
/* Reparse conditions, they might contain references to the
old symtab. */
@@ -11660,16 +11541,6 @@ update_breakpoint_locations (struct breakpoint *b,
}
}
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sals.sals[i].symtab->filename);
-
- if (b->line_number == 0)
- b->line_number = sals.sals[i].line;
-
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
@@ -11736,7 +11607,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
char *s;
int marker_spec;
struct symtabs_and_lines sals = {0};
- struct gdb_exception e;
+ volatile struct gdb_exception e;
s = addr_string;
marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
@@ -11757,7 +11628,30 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
error (_("marker %s not found"), tp->static_trace_marker_id);
}
else
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ {
+ struct linespec_result canonical;
+
+ init_linespec_result (&canonical);
+ decode_line_full (&s, 1, (struct symtab *) NULL, 0,
+ &canonical, multiple_symbols_all,
+ b->filter);
+
+ /* We should get 0 or 1 resulting SALs. */
+ gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
+
+ if (VEC_length (linespec_sals, canonical.sals) > 0)
+ {
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ sals = lsal->sals;
+ /* Arrange it so the destructor does not free the
+ contents. */
+ lsal->sals.sals = NULL;
+ }
+
+ destroy_linespec_result (&canonical);
+ }
}
if (e.reason < 0)
{
@@ -11791,9 +11685,10 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
{
- gdb_assert (sals.nelts == 1);
+ int i;
- resolve_sal_pc (&sals.sals[0]);
+ for (i = 0; i < sals.nelts; ++i)
+ resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
char *cond_string = 0;
@@ -11836,7 +11731,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals.sals);
- expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = sals;
}
if (b->addr_string_range_end)
@@ -11845,7 +11740,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals_end.sals);
- expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ expanded_end = sals_end;
}
}
@@ -12383,11 +12278,10 @@ decode_line_spec_1 (char *string, int funfirstline)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&string, funfirstline,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, NULL);
+ (struct symtab *) NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 94e324a..bb99600 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -393,6 +393,14 @@ struct bp_location
This variable keeps a number of events still to go, when
it becomes 0 this location is retired. */
int events_till_retirement;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ char *source_file;
};
/* This structure is a collection of function pointers that, if available,
@@ -540,14 +548,6 @@ struct breakpoint
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
- /* Line number of this address. */
-
- int line_number;
-
- /* Source file name of this address. */
-
- char *source_file;
-
/* Non-zero means a silent breakpoint (don't print frame info
if we stop here). */
unsigned char silent;
@@ -571,6 +571,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
+ /* The filter that should be passed to decode_line_full when
+ re-setting this breakpoint. This may be NULL, but otherwise is
+ allocated with xmalloc. */
+ char *filter;
+
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 94328c4..bc76864 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -92,6 +92,9 @@ void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
@@ -246,16 +249,6 @@ help_command (char *command, int from_tty)
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
@@ -796,8 +789,9 @@ edit_command (char *arg, int from_tty)
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
@@ -926,8 +920,9 @@ list_command (char *arg, int from_tty)
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
@@ -959,9 +954,10 @@ list_command (char *arg, int from_tty)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals_end = decode_line_list (&arg1, 0, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ sals_end = decode_line_list (&arg1, 0, sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
@@ -1472,6 +1468,85 @@ ambiguous_line_spec (struct symtabs_and_lines *sals)
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ || sals->sals[i].symtab == NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
diff --git a/gdb/defs.h b/gdb/defs.h
index d0b6813..0e6e629 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -428,6 +428,7 @@ char *ldirname (const char *filename);
char **gdb_buildargv (const char *);
int compare_positive_ints (const void *ap, const void *bp);
+int compare_strings (const void *ap, const void *bp);
/* A wrapper for bfd_errmsg to produce a more helpful error message
in the case of bfd_error_file_ambiguously recognized.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8a7d7e9..7547a40 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -443,9 +443,6 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
return sym;
}
-/* Define VEC (CORE_ADDR) functions. */
-DEF_VEC_I (CORE_ADDR);
-
/* Verify function with entry point exact address ADDR can never call itself
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
can call itself via tail calls.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 84eb589..145c8d0 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2438,10 +2438,38 @@ dw2_forget_cached_source_info (struct objfile *objfile)
dw2_free_cached_file_names, NULL);
}
+/* Helper function for dw2_map_symtabs_matching_filename that expands
+ the symtabs and calls the iterator. */
+
+static int
+dw2_map_expand_apply (struct objfile *objfile,
+ struct dwarf2_per_cu_data *per_cu,
+ const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded CUs. */
+ if (per_cu->v.quick->symtab)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ dw2_instantiate_symtab (objfile, per_cu);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
static int
-dw2_lookup_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
+dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
{
int i;
int check_basename = lbasename (name) == name;
@@ -2469,8 +2497,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (FILENAME_CMP (name, this_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
if (check_basename && ! base_cu
@@ -2485,8 +2515,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (full_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
@@ -2498,8 +2530,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
}
@@ -2507,8 +2541,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (base_cu)
{
- *result = dw2_instantiate_symtab (objfile, base_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, base_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
return 0;
@@ -2850,7 +2886,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
- dw2_lookup_symtab,
+ dw2_map_symtabs_matching_filename,
dw2_lookup_symbol,
dw2_pre_expand_symtabs_matching,
dw2_print_stats,
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 37ec368..11571dd 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -44,108 +44,246 @@
#include <ctype.h>
#include "cli/cli-utils.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_variable (struct linespec_state *self,
+ char *copy);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symtab *symtab_from_filename (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 symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+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_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+/* Helper functions. */
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Add SAL to SALS. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+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 decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* 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 symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+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);
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+ if (self->canonical)
+ {
+ char *canonical_name = NULL;
-/* Helper functions. */
+ self->canonical_names = xrealloc (self->canonical_names,
+ sals->nelts * sizeof (char *));
+ if (sal->symtab && sal->symtab->filename)
+ {
+ char *filename = sal->symtab->filename;
+
+ /* FIXME: this is where we should do "FILE:FUNCTION:LINE",
+ to let us distinguish between different template
+ instantiations. */
+ 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
@@ -180,26 +318,64 @@ 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 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 (strcmp_iw (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;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
+ if (pspace->executing_startup)
+ continue;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ set_current_program_space (pspace);
- return count;
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+ iterate_name_matcher,
+ ALL_DOMAIN,
+ &name);
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ iterate_over_symbols (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -226,40 +402,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);
@@ -287,181 +447,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;
-}
-
-/* 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;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-
-
/* 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 ','
@@ -517,147 +528,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
{
@@ -665,14 +683,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". */
@@ -812,13 +826,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
@@ -835,21 +846,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);
@@ -876,7 +892,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)
@@ -902,10 +925,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? */
@@ -933,14 +958,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);
@@ -953,12 +980,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. */
@@ -973,9 +1004,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. */
@@ -998,10 +1030,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). */
@@ -1041,91 +1078,238 @@ 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;
+ }
}
-\f
+/* A constructor for linespec_state. */
-/* 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. */
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int funfirstline,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = funfirstline;
+ 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);
+}
-/* First, some functions to initialize stuff at the beggining of the
- function. */
+/* A destructor for linespec_state. */
static void
-initialize_defaults (struct symtab **default_symtab, int *default_line)
+linespec_state_destructor (void *arg)
{
- if (*default_symtab == 0)
- {
- /* Use whatever we have for the default source line. We don't use
- get_current_or_default_symtab_and_line as it can recurse and call
- us back! */
- struct symtab_and_line cursal =
- get_current_source_symtab_and_line ();
-
- *default_symtab = cursal.symtab;
- *default_line = cursal.line;
- }
-}
+ struct linespec_state *self = arg;
-\f
+ xfree (self->user_filename);
+ xfree (self->user_function);
+ VEC_free (symtab_p, self->file_symtabs);
+ htab_delete (self->addr_set);
+}
-/* Decode arg of the form *PC. */
+/* See linespec.h. */
-static struct symtabs_and_lines
-decode_indirect (char **argptr)
+void
+decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter)
{
- struct symtabs_and_lines values;
- CORE_ADDR pc;
+ 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);
+
+ linespec_state_constructor (&state, funfirstline, 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;
+
+ 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 funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, 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;
+}
+
+/* See linespec.h. */
+
+struct symtabs_and_lines
+decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, default_symtab,
+ default_line, NULL);
+ state.list_mode = 1;
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+\f
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+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));
@@ -1138,6 +1322,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;
}
@@ -1235,8 +1422,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)
@@ -1264,94 +1450,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,
- ¤t_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
@@ -1360,9 +1504,8 @@ 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;
@@ -1370,10 +1513,9 @@ decode_compound (char **argptr, int funfirstline,
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. */
@@ -1408,8 +1550,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
@@ -1509,15 +1650,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
@@ -1567,9 +1707,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. */
@@ -1579,8 +1717,10 @@ 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. */
@@ -1600,7 +1740,6 @@ decode_compound (char **argptr, int funfirstline,
/* Look up entire name. */
name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
@@ -1608,213 +1747,400 @@ decode_compound (char **argptr, int funfirstline,
make_cleanup (xfree, name);
}
- 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;
+ return decode_variable (self, copy);
+}
- /* 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);
- }
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* 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);
-}
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
+
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
+
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
-/* Next come some helper functions for decode_compound. */
+ 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);
+ }
+
+ 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);
+ iterate_over_symbols (search_block, copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ 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;
+}
- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
- file_symtab);
+/* 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;
- /* 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)
+ for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix)
+ add_matching_symbols_to_info (iter, info, pspace);
+}
+
+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);
+
+ 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);
+}
+
+\f
+
+/* 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;
}
-\f
+/* 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;
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+ 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);
+ }
+
+ do_cleanups (cleanups);
+ return collector.symtabs;
+}
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+/* Return all the symtabs associated to the filename given by the
+ substring of *ARGPTR ending at P, and advance ARGPTR past that
+ filename. */
+
+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] == '"')
@@ -1823,9 +2149,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,
@@ -1836,31 +2162,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] == '"')
@@ -1869,18 +2211,40 @@ 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 looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (VEC_empty (symbolp, result)
+ && current_language->la_language == language_ada)
+ {
+ struct symbol *function_symbol;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ xfree (copy);
+ copy = xstrdup (SYMBOL_SEARCH_NAME (function_symbol));
+ *user_function = copy;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols,
+ &result, NULL);
+ }
+ }
+
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ return result;
}
\f
@@ -1890,13 +2254,16 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
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 ix;
+ struct symtab *elt;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1904,12 +2271,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
@@ -1917,11 +2281,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 == '+')
@@ -1934,14 +2306,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;
@@ -1949,28 +2321,77 @@ 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);
+
+ 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));
+
+ if (self->list_mode)
+ {
+ /* 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);
+ }
+ else
+ {
+ int pcix;
+ CORE_ADDR pc;
+ VEC (CORE_ADDR) *pcs;
+
+ pcs = find_pcs_for_symtab_line (elt, val.line);
+ if (VEC_empty (CORE_ADDR, pcs))
+ continue;
+
+ for (pcix = 0; VEC_iterate (CORE_ADDR, pcs, pcix, pc); ++pcix)
+ {
+ val.symtab = elt;
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = pc;
+ val.explicit_line = 1;
+
+ skip_prologue_sal (&val);
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
+
+ VEC_free (CORE_ADDR, pcs);
+ }
+ }
+
+ 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;
}
@@ -1979,17 +2400,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')
@@ -2011,19 +2432,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 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.reason == 0)
+ return values;
+
+ 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))
@@ -2033,18 +2453,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;
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ 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;
}
@@ -2053,7 +2492,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.
@@ -2062,78 +2501,308 @@ 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)
{
+ 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_selected_block (0);
+
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;
+ }
+
+ 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)
+ {
+ 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;
+
+ 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, ¤t_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);
+}
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+/* Search minimal symbols in all objfiles for NAME. If SEARCH_PSPACE
+ is not NULL, the search is restricted to just that program
+ space. */
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+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;
- return sym != NULL;
+ 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));
+ 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);
+ 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);
+
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
- name = canon;
- make_cleanup (xfree, name);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (sym != NULL)
+ /* If looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (info.result.nelts == 0 && current_language->la_language == language_ada)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
- }
+ struct symbol *sym;
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ sym = lookup_symbol (lookup_name, get_selected_block (0), VAR_DOMAIN, 0);
+ if (sym)
+ {
+ copy = SYMBOL_SEARCH_NAME (sym);
+ add_matching_symbols_to_info (copy, &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);
}
@@ -2142,130 +2811,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,
- ¤t_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;
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+ 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);
+}
- values.nelts = 1;
- return values;
+/* Cleanup function for a linespec_result. */
+
+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);
}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 3c86af3..d32f401 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -20,8 +20,30 @@
struct symtab;
+#include "vec.h"
+
+/* decode_line_full returns a vector of these. */
+
+struct linespec_sals
+{
+ /* This is the linespec corresponding to the sals contained in this
+ object. It can be passed as the FILTER argument to future calls
+ to decode_line_full. This is freed by
+ destroy_linespec_result. */
+ char *canonical;
+
+ /* Sals. The 'sals' field is destroyed by
+ destroy_linespec_result. */
+ struct symtabs_and_lines sals;
+};
+
+typedef struct linespec_sals linespec_sals;
+DEF_VEC_O (linespec_sals);
+
/* An instance of this may be filled in by decode_line_1. The caller
- must call init_linespec_result to initialize it. */
+ must call init_linespec_result to initialize it and
+ destroy_linespec_result to destroy it. The caller must make copies
+ of any data that it needs to keep. */
struct linespec_result
{
@@ -30,22 +52,85 @@ struct linespec_result
display mechanism would do the wrong thing. */
int special_display;
- /* If non-NULL, an array of canonical names for returned
- symtab_and_line objects. The array has as many elements as the
- `nelts' field in the symtabs_and_line returned by decode_line_1.
- An element in the array may be NULL. The array and each non-NULL
- element in it are allocated with xmalloc and must be freed by the
- caller. */
- char **canonical;
+ /* If non-zero, the linespec result should be considered to be a
+ "pre-expanded" multi-location linespec. A pre-expanded linespec
+ holds all matching locations in a single linespec_sals
+ object. */
+ int pre_expanded;
+
+ /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+ by the user. This will be freed by destroy_linespec_result. */
+ char *addr_string;
+
+ /* The sals. The vector will be freed by
+ destroy_linespec_result. */
+ VEC (linespec_sals) *sals;
};
/* Initialize a linespec_result. */
extern void init_linespec_result (struct linespec_result *);
+/* Destroy a linespec_result. */
+
+extern void destroy_linespec_result (struct linespec_result *);
+
+/* Return a cleanup that destroys a linespec_result. */
+
+extern struct cleanup *
+ make_cleanup_destroy_linespec_result (struct linespec_result *);
+
extern struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline,
- struct symtab *default_symtab, int default_line,
- struct linespec_result *canonical);
+ struct symtab *default_symtab, int default_line);
+
+/* Like decode_line_1, but useful only for the 'list' command. With
+ this variant, a "file:line" linespec will always return a result. */
+
+extern struct symtabs_and_lines
+ decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line);
+
+/* Parse *ARGPTR as a linespec and return results. This is the "full"
+ interface to this module, which handles multiple results
+ properly.
+
+ FUNFIRSTLINE is nonzero if we want the resulting SALs to describe
+ the first line of indicated functions.
+
+ DEFAULT_SYMTAB and DEFAULT_LINE describe the default location.
+ DEFAULT_SYMTAB can be NULL, in which case the current symtab and
+ line are used.
+
+ CANONICAL is where the results are stored. It must not be NULL.
+
+ SELECT_MODE must be one of the multiple_symbols_* constants, or
+ NULL. It determines how multiple results will be handled. If
+ NULL, the appropriate CLI value will be used.
+
+ FILTER can either be NULL or a string holding a canonical name.
+ This is only valid when SELECT_MODE is multiple_symbols_all.
+
+ Multiple results are handled differently depending on the
+ arguments:
+
+ . With multiple_symbols_cancel, an exception is thrown.
+
+ . With multiple_symbols_ask, a menu is presented to the user. The
+ user may select none, in which case an exception is thrown; or all,
+ which is handled like multiple_symbols_all, below. Otherwise,
+ CANONICAL->SALS will have one entry for each name the user chose.
+
+ . With multiple_symbols_all, CANONICAL->SALS will have a single
+ entry describing all the matching locations. If FILTER is
+ non-NULL, then only locations whose canonical name is equal (in the
+ strcmp sense) to FILTER will be returned; all others will be
+ filtered out. */
+
+extern void decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter);
#endif /* defined (LINESPEC_H) */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 70871cd..f90f036 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -310,6 +310,46 @@ lookup_minimal_symbol (const char *name, const char *sfile,
return NULL;
}
+/* Iterate over all the minimal symbols in the objfile OBJF which
+ match NAME. Both the ordinary and demangled names of each symbol
+ are considered. The caller is responsible for canonicalizing NAME,
+ should that need to be done.
+
+ For each matching symbol, CALLBACK is called with the symbol and
+ USER_DATA as arguments. */
+
+void
+iterate_over_minimal_symbols (struct objfile *objf, const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data)
+{
+ unsigned int hash;
+ struct minimal_symbol *iter;
+ int (*cmp) (const char *, const char *);
+
+ /* The first pass is over the ordinary hash table. */
+ hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_hash[hash];
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+ while (iter)
+ {
+ if (cmp (SYMBOL_LINKAGE_NAME (iter), name) == 0)
+ (*callback) (iter, user_data);
+ iter = iter->hash_next;
+ }
+
+ /* The second pass is over the demangled table. */
+ hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_demangled_hash[hash];
+ while (iter)
+ {
+ if (SYMBOL_MATCHES_SEARCH_NAME (iter, name))
+ (*callback) (iter, user_data);
+ iter = iter->demangled_hash_next;
+ }
+}
+
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a pointer
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 592b52e..dcf9459 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -952,49 +952,7 @@ classes_info (char *regexp, int from_tty)
printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
-/*
- * Function: find_imps (char *selector, struct symbol **sym_arr)
- *
- * Input: a string representing a selector
- * a pointer to an array of symbol pointers
- * possibly a pointer to a symbol found by the caller.
- *
- * Output: number of methods that implement that selector. Side
- * effects: The array of symbol pointers is filled with matching syms.
- *
- * By analogy with function "find_methods" (symtab.c), builds a list
- * of symbols matching the ambiguous input, so that "decode_line_2"
- * (symtab.c) can list them and ask the user to choose one or more.
- * In this case the matches are objective c methods
- * ("implementations") matching an objective c selector.
- *
- * Note that it is possible for a normal (c-style) function to have
- * the same name as an objective c selector. To prevent the selector
- * from eclipsing the function, we allow the caller (decode_line_1) to
- * search for such a function first, and if it finds one, pass it in
- * to us. We will then integrate it into the list. We also search
- * for one here, among the minsyms.
- *
- * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
- * into two parts: debuggable (struct symbol) syms, and
- * non_debuggable (struct minimal_symbol) syms. The debuggable
- * ones will come first, before NUM_DEBUGGABLE (which will thus
- * be the index of the first non-debuggable one).
- */
-
-/*
- * Function: total_number_of_imps (char *selector);
- *
- * Input: a string representing a selector
- * Output: number of methods that implement that selector.
- *
- * By analogy with function "total_number_of_methods", this allows
- * decode_line_1 (symtab.c) to detect if there are objective c methods
- * matching the input, and to allocate an array of pointers to them
- * which can be manipulated by "decode_line_2" (also in symtab.c).
- */
-
-char *
+static char *
parse_selector (char *method, char **selector)
{
char *s1 = NULL;
@@ -1050,7 +1008,7 @@ parse_selector (char *method, char **selector)
return s2;
}
-char *
+static char *
parse_method (char *method, char *type, char **class,
char **category, char **selector)
{
@@ -1154,15 +1112,11 @@ parse_method (char *method, char *type, char **class,
}
static void
-find_methods (struct symtab *symtab, char type,
- const char *class, const char *category,
- const char *selector, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+find_methods (char type, const char *class, const char *category,
+ const char *selector,
+ VEC (const_char_ptr) **symbol_names)
{
struct objfile *objfile = NULL;
- struct minimal_symbol *msymbol = NULL;
- struct block *block = NULL;
- struct symbol *sym = NULL;
char *symname = NULL;
@@ -1171,21 +1125,15 @@ find_methods (struct symtab *symtab, char type,
char *ncategory = NULL;
char *nselector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
static char *tmp = NULL;
static unsigned int tmplen = 0;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
-
- if (symtab)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ gdb_assert (symbol_names != NULL);
ALL_OBJFILES (objfile)
{
unsigned int *objc_csym;
+ struct minimal_symbol *msymbol = NULL;
/* The objfile_csym variable counts the number of ObjC methods
that this objfile defines. We save that count as a private
@@ -1202,7 +1150,6 @@ find_methods (struct symtab *symtab, char type,
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
QUIT;
@@ -1216,18 +1163,8 @@ find_methods (struct symtab *symtab, char type,
/* Not a method name. */
continue;
- /* 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, pc,
- ¤t_target);
-
objfile_csym++;
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
/* Now that thinks are a bit sane, clean up the symname. */
while ((strlen (symname) + 1) >= tmplen)
{
@@ -1255,41 +1192,9 @@ find_methods (struct symtab *symtab, char type,
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
- sym = find_pc_function (pc);
- if (sym != NULL)
- {
- const char *newsymname = SYMBOL_NATURAL_NAME (sym);
-
- if (strcmp (symname, newsymname) == 0)
- {
- /* Found a high-level method sym: swap it into the
- lower part of sym_arr (below num_debuggable). */
- if (syms != NULL)
- {
- syms[csym] = syms[cdebug];
- syms[cdebug] = sym;
- }
- csym++;
- cdebug++;
- }
- else
- {
- warning (
-"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
- newsymname, symname);
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
- }
- else
- {
- /* Found a non-debuggable method symbol. */
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
+ VEC_safe_push (const_char_ptr, *symbol_names, symname);
}
+
if (objc_csym == NULL)
{
objc_csym = obstack_alloc (&objfile->objfile_obstack,
@@ -1301,38 +1206,79 @@ find_methods (struct symtab *symtab, char type,
/* Count of ObjC methods in this objfile should be constant. */
gdb_assert (*objc_csym == objfile_csym);
}
+}
+
+/* Uniquify a VEC of strings. */
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
+static void
+uniquify_strings (VEC (const_char_ptr) **strings)
+{
+ int ix;
+ const char *elem, *last = NULL;
+ int out;
+
+ qsort (VEC_address (const_char_ptr, *strings),
+ VEC_length (const_char_ptr, *strings),
+ sizeof (const_char_ptr),
+ compare_strings);
+ out = 0;
+ for (ix = 0; VEC_iterate (const_char_ptr, *strings, ix, elem); ++ix)
+ {
+ if (last == NULL || strcmp (last, elem) != 0)
+ {
+ /* Keep ELEM. */
+ VEC_replace (const_char_ptr, *strings, out, elem);
+ ++out;
+ }
+ last = elem;
+ }
+ VEC_truncate (const_char_ptr, *strings, out);
}
-char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+char *
+find_imps (char *method, VEC (const_char_ptr) **symbol_names)
{
char type = '\0';
char *class = NULL;
char *category = NULL;
char *selector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
- unsigned int ncsym = 0;
- unsigned int ncdebug = 0;
-
char *buf = NULL;
char *tmp = NULL;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
+ int selector_case = 0;
- if (nsym != NULL)
- *nsym = 0;
- if (ndebug != NULL)
- *ndebug = 0;
+ gdb_assert (symbol_names != NULL);
buf = (char *) alloca (strlen (method) + 1);
strcpy (buf, method);
@@ -1340,99 +1286,37 @@ char *find_imps (struct symtab *symtab, struct block *block,
if (tmp == NULL)
{
- struct symbol *sym = NULL;
- struct minimal_symbol *msym = NULL;
-
strcpy (buf, method);
tmp = parse_selector (buf, &selector);
if (tmp == NULL)
return NULL;
- sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
- if (sym != NULL)
- {
- if (syms)
- syms[csym] = sym;
- csym++;
- cdebug++;
- }
-
- if (sym == NULL)
- msym = lookup_minimal_symbol (selector, 0, 0);
-
- if (msym != NULL)
- {
- if (syms)
- syms[csym] = (struct symbol *)msym;
- csym++;
- }
+ selector_case = 1;
}
- if (syms != NULL)
- find_methods (symtab, type, class, category, selector,
- syms + csym, &ncsym, &ncdebug);
- else
- find_methods (symtab, type, class, category, selector,
- NULL, &ncsym, &ncdebug);
-
- /* If we didn't find any methods, just return. */
- if (ncsym == 0 && ncdebug == 0)
- return method;
+ find_methods (type, class, category, selector, symbol_names);
- /* Take debug symbols from the second batch of symbols and swap them
- * with debug symbols from the first batch. Repeat until either the
- * second section is out of debug symbols or the first section is
- * full of debug symbols. Either way we have all debug symbols
- * packed to the beginning of the buffer.
- */
-
- if (syms != NULL)
+ /* If we hit the "selector" case, and we found some methods, then
+ add the selector itself as a symbol, if it exists. */
+ if (selector_case && !VEC_empty (const_char_ptr, *symbol_names))
{
- while ((cdebug < csym) && (ncdebug > 0))
+ struct symbol *sym = lookup_symbol (selector, NULL, VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (sym));
+ else
{
- struct symbol *s = NULL;
- /* First non-debugging symbol. */
- unsigned int i = cdebug;
- /* Last of second batch of debug symbols. */
- unsigned int j = csym + ncdebug - 1;
-
- s = syms[j];
- syms[j] = syms[i];
- syms[i] = s;
-
- /* We've moved a symbol from the second debug section to the
- first one. */
- cdebug++;
- ncdebug--;
+ struct minimal_symbol *msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (msym));
}
}
- csym += ncsym;
- cdebug += ncdebug;
-
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
-
- if (syms == NULL)
- return method + (tmp - buf);
-
- if (csym > 1)
- {
- /* Sort debuggable symbols. */
- if (cdebug > 1)
- qsort (syms, cdebug, sizeof (struct minimal_symbol *),
- compare_classes);
-
- /* Sort minimal_symbols. */
- if ((csym - cdebug) > 1)
- qsort (&syms[cdebug], csym - cdebug,
- sizeof (struct minimal_symbol *), compare_classes);
- }
- /* Terminate the sym_arr list. */
- syms[csym] = 0;
+ uniquify_strings (symbol_names);
return method + (tmp - buf);
}
diff --git a/gdb/objc-lang.h b/gdb/objc-lang.h
index ee4cc29..351af7b 100644
--- a/gdb/objc-lang.h
+++ b/gdb/objc-lang.h
@@ -21,6 +21,8 @@
#if !defined(OBJC_LANG_H)
#define OBJC_LANG_H
+#include "cp-support.h" /* For VEC (const_char_ptr) */
+
struct stoken;
struct value;
@@ -39,15 +41,7 @@ extern char *objc_demangle (const char *mangled, int options);
extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
-extern char *parse_selector (char *method, char **selector);
-
-extern char *parse_method (char *method, char *type,
- char **class, char **category,
- char **selector);
-
-extern char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug);
+extern char *find_imps (char *method, VEC (const_char_ptr) **symbol_names);
extern struct value *value_nsstring (struct gdbarch *gdbarch,
char *ptr, int len);
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 1f3b3dc..2a1a879 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -125,13 +125,42 @@ require_partial_symbols (struct objfile *objfile, int verbose)
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p)
-/* Lookup the partial symbol table of a source file named NAME.
- *If* there is no '/' in the name, a match after a '/'
- in the psymtab filename will also work. */
+/* Helper function for partial_map_symtabs_matching_filename that
+ expands the symtabs and calls the iterator. */
-static struct partial_symtab *
-lookup_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path)
+static int
+partial_map_expand_apply (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ struct partial_symtab *pst,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded psymtabs. */
+ if (pst->readin)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ psymtab_to_symtab (pst);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
+static int
+partial_map_symtabs_matching_filename (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data)
{
struct partial_symtab *pst;
@@ -139,7 +168,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
/* If the user gave us an absolute path, try to find the file in
@@ -150,7 +181,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
if (pst->fullname != NULL
&& FILENAME_CMP (full_path, pst->fullname) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
@@ -165,7 +198,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
}
if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
}
@@ -176,29 +211,12 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path, pst,
+ callback, data))
+ return 1;
}
- return (NULL);
-}
-
-static int
-lookup_symtab_via_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
-{
- struct partial_symtab *ps;
-
- ps = lookup_partial_symtab (objfile, name, full_path, real_path);
- if (!ps)
- return 0;
-
- if (ps->readin)
- error (_("Internal: readin %s pst for `%s' found when no symtab found."),
- ps->filename, name);
-
- *result = PSYMTAB_TO_SYMTAB (ps);
- return 1;
+ return 0;
}
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
@@ -1288,7 +1306,7 @@ const struct quick_symbol_functions psym_functions =
objfile_has_psyms,
find_last_source_symtab_from_partial,
forget_cached_source_info_partial,
- lookup_symtab_via_partial_symtab,
+ partial_map_symtabs_matching_filename,
lookup_symbol_aux_psymtabs,
pre_expand_symtabs_matching_psymtabs,
print_psymtab_stats_for_objfile,
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 67696fd..8ab6631 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -843,7 +843,7 @@ DEF_VEC_O (type_equality_entry_d);
the same, 0 otherwise. Handles NULLs properly. */
static int
-compare_strings (const char *s, const char *t)
+compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
@@ -879,9 +879,10 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
- if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
+ TYPE_TAG_NAME (type2)))
return Py_NE;
- if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
@@ -904,7 +905,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
- if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_NAME (*field1),
+ FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
@@ -918,8 +920,8 @@ check_types_equal (struct type *type1, struct type *type2,
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
- if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
- FIELD_STATIC_PHYSNAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
+ FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 108e542..b898313 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -512,7 +512,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
{
copy = xstrdup (arg);
make_cleanup (xfree, copy);
- sals = decode_line_1 (©, 0, 0, 0, 0);
+ sals = decode_line_1 (©, 0, 0, 0);
make_cleanup (xfree, sals.sals);
}
else
diff --git a/gdb/skip.c b/gdb/skip.c
index 4bda3c4..29c7521 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -164,7 +164,7 @@ skip_function_command (char *arg, int from_tty)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&arg, 1, 0, 0, 0);
+ sals = decode_line_1 (&arg, 1, 0, 0);
}
if (decode_exception.reason < 0)
@@ -514,7 +514,7 @@ skip_re_set (void)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&func_name, 1, 0, 0, 0);
+ sals = decode_line_1 (&func_name, 1, 0, 0);
}
if (decode_exception.reason >= 0
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 888aa34..21efbdf 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -28,8 +28,6 @@
#include "gdb_string.h"
-DEF_VEC_I(CORE_ADDR);
-
/* Private data for each loaded library. */
struct lm_info
{
diff --git a/gdb/source.c b/gdb/source.c
index 6e29172..f68a855 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1408,12 +1408,14 @@ line_info (char *arg, int from_tty)
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
@@ -1427,11 +1429,15 @@ line_info (char *arg, int from_tty)
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
@@ -1497,7 +1503,7 @@ line_info (char *arg, int from_tty)
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */
diff --git a/gdb/stack.c b/gdb/stack.c
index 9136daa..48c1c27 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2444,20 +2444,25 @@ func_command (char *arg, int from_tty)
int i;
int level = 1;
struct function_bounds *func_bounds = NULL;
+ struct cleanup *cleanups;
if (arg != NULL)
return;
frame = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
+ cleanups = make_cleanup (xfree, sals.sals);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
+ make_cleanup (xfree, func_bounds);
for (i = 0; (i < sals.nelts && !found); i++)
{
- if (sals.sals[i].pc == 0
- || find_pc_partial_function (sals.sals[i].pc, NULL,
- &func_bounds[i].low,
- &func_bounds[i].high) == 0)
+ if (sals.sals[i].pspace != current_program_space)
+ func_bounds[i].low = func_bounds[i].high = 0;
+ else if (sals.sals[i].pc == 0
+ || find_pc_partial_function (sals.sals[i].pc, NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
{
func_bounds[i].low = func_bounds[i].high = 0;
}
@@ -2476,8 +2481,7 @@ func_command (char *arg, int from_tty)
}
while (!found && level == 0);
- if (func_bounds)
- xfree (func_bounds);
+ do_cleanups (cleanups);
if (!found)
printf_filtered (_("'%s' not within current stack frame.\n"), arg);
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 624df76..d45a226 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -152,22 +152,24 @@ struct quick_symbol_functions
/* Forget all cached full file names for OBJFILE. */
void (*forget_cached_source_info) (struct objfile *objfile);
- /* Look up the symbol table, in OBJFILE, of a source file named
- NAME. If there is no '/' in the name, a match after a '/' in the
- symbol table's file name will also work. FULL_PATH is the
- absolute file name, and REAL_PATH is the same, run through
- gdb_realpath.
-
- If no such symbol table can be found, returns 0.
-
- Otherwise, sets *RESULT to the symbol table and returns 1. This
- might return 1 and set *RESULT to NULL if the requested file is
- an include file that does not have a symtab of its own. */
- int (*lookup_symtab) (struct objfile *objfile,
- const char *name,
- const char *full_path,
- const char *real_path,
- struct symtab **result);
+ /* Expand and iterate over each "partial" symbol table in OBJFILE
+ where the source file is named NAME.
+
+ If there is no '/' in the name, a match after a '/' in the symbol
+ table's file name will also work. FULL_PATH is the absolute file
+ name, and REAL_PATH is the same, run through gdb_realpath.
+
+ If a match is found, the "partial" symbol table is expanded.
+ Then, this calls iterate_over_some_symtabs (or equivalent) over
+ all newly-created symbol tables, passing CALLBACK and DATA to it.
+ The result of this call is returned. */
+ int (*map_symtabs_matching_filename) (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data);
/* Check to see if the symbol is defined in a "partial" symbol table
of OBJFILE. KIND should be either GLOBAL_BLOCK or STATIC_BLOCK,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f881226..0d803aa 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -81,7 +81,7 @@ static void sources_info (char *, int);
static void output_source_filename (const char *, int *);
-static int find_line_common (struct linetable *, int, int *);
+static int find_line_common (struct linetable *, int, int *, int);
static struct symbol *lookup_symbol_aux (const char *name,
const struct block *block,
@@ -142,43 +142,36 @@ multiple_symbols_select_mode (void)
const struct block *block_found;
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
+/* Check for a symtab of a specific name by searching some symtabs.
+ This is a helper function for callbacks of iterate_over_symtabs.
-struct symtab *
-lookup_symtab (const char *name)
+ The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA
+ are identical to the `map_symtabs_matching_filename' method of
+ quick_symbol_functions.
+
+ FIRST and AFTER_LAST indicate the range of symtabs to search.
+ AFTER_LAST is one past the last symtab to search; NULL means to
+ search until the end of the list. */
+
+int
+iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last)
{
- int found;
struct symtab *s = NULL;
- struct objfile *objfile;
- char *real_path = NULL;
- char *full_path = NULL;
- struct cleanup *cleanup;
- cleanup = make_cleanup (null_cleanup, NULL);
-
- /* Here we are interested in canonicalizing an absolute path, not
- absolutizing a relative path. */
- if (IS_ABSOLUTE_PATH (name))
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- full_path = xfullpath (name);
- make_cleanup (xfree, full_path);
- real_path = gdb_realpath (name);
- make_cleanup (xfree, real_path);
- }
-
-got_symtab:
-
- /* First, search for an exact match. */
-
- ALL_SYMTABS (objfile, s)
- {
- if (FILENAME_CMP (name, s->filename) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
/* If the user gave us an absolute path, try to find the file in
this symtab and use its absolute path. */
@@ -189,8 +182,8 @@ got_symtab:
if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
{
- do_cleanups (cleanup);
- return s;
+ if (callback (s, data))
+ return 1;
}
}
@@ -204,62 +197,114 @@ got_symtab:
make_cleanup (xfree, rp);
if (FILENAME_CMP (real_path, rp) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
- }
+ }
/* Now, search for a matching tail (only if name doesn't have any dirs). */
if (lbasename (name) == name)
- ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- do_cleanups (cleanup);
- return s;
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
+ return 0;
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work.
+
+ Calls CALLBACK with each symtab that is found and with the supplied
+ DATA. If CALLBACK returns true, the search stops. */
+
+void
+iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data)
+{
+ struct symtab *s = NULL;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ if (iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, NULL))
+ {
+ do_cleanups (cleanups);
+ return;
+ }
+ }
+
/* Same search rules as above apply here, but now we look thru the
psymtabs. */
- found = 0;
ALL_OBJFILES (objfile)
{
if (objfile->sf
- && objfile->sf->qf->lookup_symtab (objfile, name, full_path, real_path,
- &s))
+ && objfile->sf->qf->map_symtabs_matching_filename (objfile,
+ name,
+ full_path,
+ real_path,
+ callback,
+ data))
{
- found = 1;
- break;
+ do_cleanups (cleanups);
+ return;
}
}
- if (s != NULL)
- {
- do_cleanups (cleanup);
- return s;
- }
- if (!found)
- {
- do_cleanups (cleanup);
- return NULL;
- }
+ do_cleanups (cleanups);
+}
+
+/* The callback function used by lookup_symtab. */
- /* At this point, we have located the psymtab for this file, but
- the conversion to a symtab has failed. This usually happens
- when we are looking up an include file. In this case,
- PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
- been created. So, we need to run through the symtabs again in
- order to find the file.
- XXX - This is a crock, and should be fixed inside of the
- symbol parsing routines. */
- goto got_symtab;
+static int
+lookup_symtab_callback (struct symtab *symtab, void *data)
+{
+ struct symtab **result_ptr = data;
+
+ *result_ptr = symtab;
+ return 1;
+}
+
+/* A wrapper for iterate_over_symtabs that returns the first matching
+ symtab, or NULL. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *result = NULL;
+
+ iterate_over_symtabs (name, lookup_symtab_callback, &result);
+ return result;
}
+
\f
/* Mangle a GDB method stub type. This actually reassembles the pieces of the
full method name, which consist of the class name (from T), the unadorned
@@ -994,33 +1039,16 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
return sym;
}
-/* Find the definition for a specified symbol name NAME
- in domain DOMAIN, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-/* This function has a bunch of loops in it and it would seem to be
- attractive to put in some QUIT's (though I'm not really sure
- whether it can run long enough to be really important). But there
- are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
- that there is C++ code below which can error(), but that probably
- doesn't affect these calls since they are looking for a known
- variable and thus can probably assume it will never hit the C++
- code). */
+/* Compute the demangled form of NAME as used by the various symbol
+ lookup functions. The result is stored in *RESULT_NAME. Returns a
+ cleanup which can be used to clean up the result. */
-struct symbol *
-lookup_symbol_in_language (const char *name, const struct block *block,
- const domain_enum domain, enum language lang,
- int *is_a_field_of_this)
+struct cleanup *
+demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
- struct symbol *returnval;
struct cleanup *cleanup = make_cleanup (null_cleanup, 0);
modified_name = name;
@@ -1067,6 +1095,38 @@ lookup_symbol_in_language (const char *name, const struct block *block,
}
}
+ *result_name = modified_name;
+ return cleanup;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
+
+struct symbol *
+lookup_symbol_in_language (const char *name, const struct block *block,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ const char *modified_name;
+ struct symbol *returnval;
+ struct cleanup *cleanup = demangle_for_lookup (name, lang, &modified_name);
+
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
@@ -1759,6 +1819,44 @@ lookup_block_symbol (const struct block *block, const char *name,
}
}
+/* Iterate over the symbols named NAME, matching DOMAIN, starting with
+ BLOCK.
+
+ For each symbol that matches, CALLBACK is called. The symbol and
+ DATA are passed to the callback.
+
+ If CALLBACK returns zero, the iteration ends. Otherwise, the
+ search continues. This function iterates upward through blocks.
+ When the outermost block has been finished, the function
+ returns. */
+
+void
+iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+ SYMBOL_DOMAIN (sym), domain))
+ {
+ if (!callback (sym, data))
+ return;
+ }
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+}
+
/* Find the symtab associated with PC and SECTION. Look through the
psymtabs and read in another symtab if necessary. */
@@ -2184,7 +2282,7 @@ find_line_symtab (struct symtab *symtab, int line,
/* First try looking it up in the given symtab. */
best_linetable = LINETABLE (symtab);
best_symtab = symtab;
- best_index = find_line_common (best_linetable, line, &exact);
+ best_index = find_line_common (best_linetable, line, &exact, 0);
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
@@ -2229,7 +2327,7 @@ find_line_symtab (struct symtab *symtab, int line,
&& FILENAME_CMP (symtab->fullname, s->fullname) != 0)
continue;
l = LINETABLE (s);
- ind = find_line_common (l, line, &exact);
+ ind = find_line_common (l, line, &exact, 0);
if (ind >= 0)
{
if (exact)
@@ -2260,6 +2358,86 @@ done:
return best_symtab;
}
+
+/* qsort comparison function for use by find_pcs_for_symtab_line. */
+
+static int
+compare_core_addrs (const void *a, const void *b)
+{
+ const CORE_ADDR *ca = a;
+ const CORE_ADDR *cb = b;
+
+ return (int) (ca - cb);
+}
+
+/* Given SYMTAB, return one PC per function in the symtab that exactly
+ matches LINE. Returns NULL if none matched. */
+
+VEC (CORE_ADDR) *
+find_pcs_for_symtab_line (struct symtab *symtab, int line)
+{
+ VEC (CORE_ADDR) *result = NULL;
+ int start = 0, ix;
+ struct symbol *previous_function = NULL;
+
+ /* First, collect all the PCs that are at this line. */
+ while (1)
+ {
+ int was_exact;
+ int idx;
+
+ idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+ if (idx < 0)
+ break;
+
+ if (!was_exact)
+ {
+ if (VEC_empty (CORE_ADDR, result))
+ {
+ /* We only found an inexact match. So, redo the search
+ for the found line. */
+ line = LINETABLE (symtab)->item[idx].line;
+ start = 0;
+ continue;
+ }
+ break;
+ }
+
+ VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+ start = idx + 1;
+ }
+
+ if (VEC_empty (CORE_ADDR, result))
+ return result;
+
+ qsort (VEC_address (CORE_ADDR, result), VEC_length (CORE_ADDR, result),
+ sizeof (CORE_ADDR), compare_core_addrs);
+
+ /* Remove all duplicate entries from the result. That is, each
+ function should only appear a single time. */
+ for (ix = 0; ix < VEC_length (CORE_ADDR, result); )
+ {
+ struct symbol *sym;
+ struct block *block;
+
+ block = block_for_pc (VEC_index (CORE_ADDR, result, ix));
+ sym = block ? block_containing_function (block) : NULL;
+
+ if (sym == NULL || sym == previous_function)
+ VEC_ordered_remove (CORE_ADDR, result, ix);
+ else
+ {
+ previous_function = sym;
+ ++ix;
+ }
+ }
+
+ if (VEC_length (CORE_ADDR, result) == 0)
+ VEC_free (CORE_ADDR, result);
+
+ return result;
+}
+
\f
/* Set the PC value for a given source file and line number and return true.
Returns zero for invalid line number (and sets the PC to 0).
@@ -2328,12 +2506,13 @@ find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr,
/* Given a line table and a line number, return the index into the line
table for the pc of the nearest line whose number is >= the specified one.
Return -1 if none is found. The value is >= 0 if it is an index.
+ START is the index at which to start searching the line table.
Set *EXACT_MATCH nonzero if the value returned is an exact match. */
static int
find_line_common (struct linetable *l, int lineno,
- int *exact_match)
+ int *exact_match, int start)
{
int i;
int len;
@@ -2353,7 +2532,7 @@ find_line_common (struct linetable *l, int lineno,
return -1;
len = l->nitems;
- for (i = 0; i < len; i++)
+ for (i = start; i < len; i++)
{
struct linetable_entry *item = &(l->item[i]);
@@ -4517,8 +4696,7 @@ decode_line_spec (char *string, int funfirstline)
cursal = get_current_source_symtab_and_line ();
sals = decode_line_1 (&string, funfirstline,
- cursal.symtab, cursal.line,
- NULL);
+ cursal.symtab, cursal.line);
if (*string)
error (_("Junk at end of line specification: %s"), string);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 90a6fe4..03f9a7a 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -22,6 +22,8 @@
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
+#include "vec.h"
+
/* Opaque declarations. */
struct ui_file;
struct frame_info;
@@ -1057,6 +1059,12 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern void iterate_over_minimal_symbols (struct objfile *objf,
+ const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data);
+
extern int in_gnu_ifunc_stub (CORE_ADDR pc);
/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
@@ -1307,4 +1315,30 @@ void fixup_section (struct general_symbol_info *ginfo,
struct objfile *lookup_objfile_from_block (const struct block *block);
+int iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last);
+
+void iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data);
+
+DEF_VEC_I (CORE_ADDR);
+
+VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line);
+
+void iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data);
+
+struct cleanup *demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name);
+
#endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 8b22324..d3c9cfc 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
- gdb.java gdb.mi gdb.modula2 gdb.multi \
+ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
$(SUBDIRS)
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 82206b3..fb70b3d 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4166,6 +4166,7 @@ do
"gdb.hp/gdb.aCC/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.aCC/Makefile" ;;
"gdb.hp/gdb.compat/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.compat/Makefile" ;;
"gdb.hp/gdb.defects/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.defects/Makefile" ;;
+ "gdb.linespec/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.linespec/Makefile" ;;
"gdb.mi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
"gdb.modula2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.multi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 8631442..121fd37 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -95,7 +95,7 @@ AC_OUTPUT([Makefile \
gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
- gdb.hp/gdb.defects/Makefile \
+ gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \
gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \
diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp
index 92fcc69..c5885ba 100644
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -540,8 +540,9 @@ gdb_test_multiple "catch exec" "$name" {
# Verify that GDB responds gracefully when asked to set a breakpoint
# on a nonexistent source line.
#
+gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in file .*" \
+ "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/list.exp b/gdb/testsuite/gdb.base/list.exp
index 5b9fe15..d4935ee 100644
--- a/gdb/testsuite/gdb.base/list.exp
+++ b/gdb/testsuite/gdb.base/list.exp
@@ -489,7 +489,7 @@ proc test_list_filename_and_function {} {
gdb_test "list foobar.c:main" "No source file named foobar.c.|Location not found" "list filename:function; nonexistant file"
- gdb_test "list list0.h:foobar" "Function \"foobar\" not defined.|Location not found" "list filename:function; nonexistant function"
+ gdb_test "list list0.h:foobar" "Function \"foobar\" not defined in \"list0.h\"." "list filename:function; nonexistant function"
}
diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp
index 1a9072d..bb0b914 100644
--- a/gdb/testsuite/gdb.base/sepdebug.exp
+++ b/gdb/testsuite/gdb.base/sepdebug.exp
@@ -337,7 +337,8 @@ gdb_test_multiple "catch exec" $name {
# on a nonexistent source line.
#
-gdb_test "break 999" "No line 999 in file .*" \
+gdb_test_no_output "set breakpoint pending off"
+gdb_test "break 999" "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index aa723c6..d402ebb 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -46,11 +46,6 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $binfile_lib
-if ![runto_main] then {
- fail "Can't run to main"
- return 0
-}
-
# Set a breakpoint in the binary.
gdb_test "br foo2" \
"Breakpoint.*file.*${testfile}\\.c.*" \
@@ -58,6 +53,11 @@ gdb_test "br foo2" \
delete_breakpoints
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
# Break in the library.
gdb_test "br foo" \
"Breakpoint.*file.*${libname}\\.c.*" \
@@ -67,9 +67,9 @@ gdb_test "continue" \
"Continuing.*" \
"continue"
-# This symbol is now looked up in the ELF library.
+# This symbol is now looked up in the ELF library and the binary.
gdb_test "br foo2" \
- "Breakpoint.*file.*${libname}\\.c.*" \
+ "Breakpoint.*: foo2. .2 locations..*" \
"foo2 in mdlib"
gdb_exit
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 6a99175..0438424 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -50,13 +50,13 @@ if ![runto_main] then {
# and a condition.
gdb_test "break 'Derived::Derived(int)'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
"set-breakpoint at ctor"
gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
gdb_test "break 'Derived::~Derived()'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
"set-breakpoint at dtor"
gdb_test "continue" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index d670b56..05b378c 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -62,7 +62,7 @@ set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
# Set a breakpoint with multiple locations.
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set breakpoint"
gdb_run_cmd
@@ -128,7 +128,7 @@ if { ![runto_main] } {
}
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 80c080b..933d690 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -52,7 +52,7 @@ set bp_location [gdb_get_line_number "set breakpoint here"]
# and a condition.
gdb_test "break $srcfile:$bp_location if i==1" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"initial condition: set breakpoint"
gdb_run_cmd
@@ -80,7 +80,7 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"separate condition: set breakpoint"
gdb_test_no_output "condition 1 i==1" \
@@ -177,7 +177,7 @@ if { ![runto_main] } {
}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/method2.exp b/gdb/testsuite/gdb.cp/method2.exp
index 2fa4169..29a387d 100644
--- a/gdb/testsuite/gdb.cp/method2.exp
+++ b/gdb/testsuite/gdb.cp/method2.exp
@@ -51,7 +51,7 @@ proc test_break { lang } {
"setting language $lang"
gdb_test_multiple "break A::method" "breaking in method ($lang)" {
- -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. A::method\\(A\\*\\) at .*\[\r\n\]*.3. A::method\\(int\\) at .*\[\r\n\]*\[\r\n\]*.4. A::method\\(\\) at .*\[\r\n\]*> $" {
+ -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. .*:A::method\\(A\\*\\)\[\r\n\]*.3. .*:A::method\\(int\\)\[\r\n\]*.4. .*:A::method\\(\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"breaking in method ($lang)"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index f5d4051..f5b41ab 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -130,18 +130,18 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} {
set menu_overload1arg "\\\[0\\\] cancel\r\n"
append menu_overload1arg "\\\[1\\\] all\r\n"
-append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n"
-append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n"
-append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n"
-append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n"
-append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n"
-append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n"
-append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n"
-append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n"
-append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n"
-append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n"
-append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n"
-append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n"
+append menu_overload1arg "\\\[2\\\] .*$srcfile:foo::overload1arg\\(double\\)\r\n"
+append menu_overload1arg "\\\[3\\\] .*$srcfile:foo::overload1arg\\(float\\)\r\n"
+append menu_overload1arg "\\\[4\\\] .*$srcfile:foo::overload1arg\\((unsigned long|long unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[5\\\] .*$srcfile:foo::overload1arg\\(long( int)?\\)\r\n"
+append menu_overload1arg "\\\[6\\\] .*$srcfile:foo::overload1arg\\((unsigned int|unsigned)\\)\r\n"
+append menu_overload1arg "\\\[7\\\] .*$srcfile:foo::overload1arg\\(int\\)\r\n"
+append menu_overload1arg "\\\[8\\\] .*$srcfile:foo::overload1arg\\((unsigned short|short unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[9\\\] .*$srcfile:foo::overload1arg\\(short( int)?\\)\r\n"
+append menu_overload1arg "\\\[10\\\] .*$srcfile:foo::overload1arg\\(unsigned char\\)\r\n"
+append menu_overload1arg "\\\[11\\\] .*$srcfile:foo::overload1arg\\(signed char\\)\r\n"
+append menu_overload1arg "\\\[12\\\] .*$srcfile:foo::overload1arg\\(char\\)\r\n"
+append menu_overload1arg "\\\[13\\\] .*$srcfile:foo::overload1arg\\((void|)\\)\r\n"
append menu_overload1arg "> $"
# Set multiple-symbols to "ask", to allow us to test the use
@@ -279,7 +279,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $decimal at $hex: file.*$srcfile, line 121.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 120.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 119.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 118.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 117.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 116.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 115.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 114.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 113.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 112.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 111.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 110.\r\nwarning: Multiple breakpoints were set.\r\nUse the .delete. command to delete unwanted breakpoints.\r\n$gdb_prompt $" {
+ -re "Breakpoint $decimal at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -306,18 +306,19 @@ gdb_expect {
gdb_test "info break" \
"Num Type\[\t \]+Disp Enb Address\[\t \]+What.*
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
+\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+<MULTIPLE>\[\t \]*\r
+\[0-9\]+.1\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
+\[0-9\]+.2\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
+\[0-9\]+.3\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
+\[0-9\]+.4\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
+\[0-9\]+.5\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
+\[0-9\]+.6\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
+\[0-9\]+.7\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
+\[0-9\]+.8\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
+\[0-9\]+.9\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
+\[0-9\]+.10\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
+\[0-9\]+.11\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
+\[0-9\]+.12\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
"breakpoint info (after setting on all)"
@@ -333,10 +334,10 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
send_gdb "continue\n"
gdb_expect {
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
pass "continue to bp overloaded : ${argtype}"
}
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
if $might_kfail {
kfail "gdb/1025" "continue to bp overloaded : ${argtype}"
} else {
@@ -352,17 +353,17 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
}
}
-continue_to_bp_overloaded 0 25 "(void|)" ""
-continue_to_bp_overloaded 1 24 "char" "arg=2 \\'\\\\002\\'"
-continue_to_bp_overloaded 1 23 "signed char" "arg=3 \\'\\\\003\\'"
-continue_to_bp_overloaded 1 22 "unsigned char" "arg=4 \\'\\\\004\\'"
-continue_to_bp_overloaded 1 21 "short" "arg=5"
-continue_to_bp_overloaded 1 20 "unsigned short" "arg=6"
-continue_to_bp_overloaded 0 19 "int" "arg=7"
-continue_to_bp_overloaded 0 18 "(unsigned|unsigned int)" "arg=8"
-continue_to_bp_overloaded 0 17 "long" "arg=9"
-continue_to_bp_overloaded 0 16 "unsigned long" "arg=10"
-continue_to_bp_overloaded 0 15 "float" "arg=100"
+continue_to_bp_overloaded 0 14 "(void|)" ""
+continue_to_bp_overloaded 1 14 "char" "arg=2 \\'\\\\002\\'"
+continue_to_bp_overloaded 1 14 "signed char" "arg=3 \\'\\\\003\\'"
+continue_to_bp_overloaded 1 14 "unsigned char" "arg=4 \\'\\\\004\\'"
+continue_to_bp_overloaded 1 14 "short" "arg=5"
+continue_to_bp_overloaded 1 14 "unsigned short" "arg=6"
+continue_to_bp_overloaded 0 14 "int" "arg=7"
+continue_to_bp_overloaded 0 14 "(unsigned|unsigned int)" "arg=8"
+continue_to_bp_overloaded 0 14 "long" "arg=9"
+continue_to_bp_overloaded 0 14 "unsigned long" "arg=10"
+continue_to_bp_overloaded 0 14 "float" "arg=100"
continue_to_bp_overloaded 1 14 "double" "arg=200"
# Test breaking on an overloaded function when multiple-symbols
@@ -375,7 +376,7 @@ gdb_test "break foo::foofunc" \
# is set to "all"
gdb_test_no_output "set multiple-symbols all"
gdb_test "break foo::foofunc" \
- "Breakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nBreakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nwarning: Multiple breakpoints were set\\.\r\nUse the \"delete\" command to delete unwanted breakpoints\\."
+ "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*"
# That's all, folks.
diff --git a/gdb/testsuite/gdb.cp/ovsrch.exp b/gdb/testsuite/gdb.cp/ovsrch.exp
index b509a25..3c3fd29 100644
--- a/gdb/testsuite/gdb.cp/ovsrch.exp
+++ b/gdb/testsuite/gdb.cp/ovsrch.exp
@@ -73,28 +73,28 @@ if {![runto_main]} {
}
# Break in A::stop_here and run tests.
-if {[gdb_breakpoint "stop_here"]} {
- pass "break stop_here"
+if {[gdb_breakpoint "A::stop_here"]} {
+ pass "break A::stop_here"
}
-if {[gdb_breakpoint "'stop_here'"]} {
- pass "break 'stop_here'"
+if {[gdb_breakpoint "'A::stop_here'"]} {
+ pass "break 'A::stop_here'"
}
gdb_continue_to_breakpoint "stop_here"
-test_class outer
+test_class A::outer
# Break in A::B::stop_here_too and run tests.
-if {[gdb_breakpoint "B::stop_here_too"]} {
- pass "break B::stop_here_too"
+if {[gdb_breakpoint "A::B::stop_here_too"]} {
+ pass "break A::B::stop_here_too"
}
-if {[gdb_breakpoint "'B::stop_here_too'"]} {
- pass "break 'B::stop_here_too'"
+if {[gdb_breakpoint "'A::B::stop_here_too'"]} {
+ pass "break 'A::B::stop_here_too'"
}
gdb_continue_to_breakpoint "stop_here_too"
-test_class inner
+test_class A::B::inner
gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.cp/re-set-overloaded.exp b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
index 2052552..bd5f3ba 100644
--- a/gdb/testsuite/gdb.cp/re-set-overloaded.exp
+++ b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
@@ -46,7 +46,6 @@ gdb_test_no_output {set variable $brk = $bpnum}
# runto or runto_main would call delete_breakpoints.
gdb_breakpoint "main"
gdb_run_cmd
-setup_kfail breakpoints/11657 *-*-*
gdb_test "" ".*" "start"
set test "breakpoint resolved"
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 6612b4a..9b1ae37 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -109,12 +109,7 @@ proc test_template_breakpoints {} {
global hp_aCC_compiler
gdb_test_multiple "break T5<int>::T5" "constructor breakpoint" {
- -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5<int>::T5\\(int\\) at .*\[\r\n\]*.3. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*\[\r\n\]*> $" {
- gdb_test "0" \
- "canceled" \
- "constructor breakpoint (obsolete format!)"
- }
- -re ".0. cancel\[\r\n\]*.1. all\[\r\n\]*.2. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*templates.cc:.*\[\r\n\]*.3. T5<int>::T5\\(int\\) at .*templates.cc:.*\[\r\n\]*> $" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\)\[\r\n\]*.3.*templates.cc:T5<int>::T5\\(int\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"constructor breakpoint"
@@ -153,7 +148,7 @@ proc test_template_breakpoints {} {
set bp_location [gdb_get_line_number \
"set breakpoint on a line with no real code"]
gdb_test "break ${testfile}.cc:${bp_location}" \
- "Breakpoint.*at.* file .*${testfile}.cc, line.*(2 locations).*" \
+ "Breakpoint.*at.*: .*${testfile}.cc:${bp_location}.*(2 locations).*" \
"breakpoint on a line with no real code"
delete_breakpoints
}
diff --git a/gdb/testsuite/gdb.linespec/Makefile.in b/gdb/testsuite/gdb.linespec/Makefile.in
new file mode 100644
index 0000000..2658a24
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/Makefile.in
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = lspec
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
new file mode 100644
index 0000000..882ccc9
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+
+
+
+
+
+int m(int x)
+{
+ return x + 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(int x)
+{
+ return x + 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
new file mode 100644
index 0000000..43917f8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+static int dupname(int y)
+{
+ label: return y;
+}
+
+int n(int y)
+{
+ return dupname(y) - 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(double x)
+{
+ return (int) x - 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
new file mode 100644
index 0000000..122a468
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -0,0 +1,106 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of ambiguous linespecs.
+
+set testfile linespec
+
+set exefile lspec
+set binfile ${objdir}/${subdir}/${exefile}
+
+set baseone base/one/thefile.cc
+set basetwo base/two/thefile.cc
+
+set hex {0x[0-9a-fA-F]+}
+
+if {[skip_cplus_tests]} {
+ unsupported linespec.exp
+ return
+}
+
+if {[prepare_for_testing ${testfile}.exp $exefile \
+ [list lspec.cc $baseone $basetwo] \
+ {debug nowarnings}]} {
+ return -1
+}
+
+gdb_test_no_output "set multiple-symbols all" \
+ "set multiple-symbols to all for linespec tests"
+
+set l1 [gdb_get_line_number "thefile breakpoint" $baseone]
+set l2 [gdb_get_line_number "thefile breakpoint" $basetwo]
+
+if {$l1 != $l2} {
+ error "somebody incompatibly modified the source files needed by linespec.exp"
+}
+
+gdb_test "break thefile.cc:$l1" \
+ "Breakpoint 1 at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
+ "multi-location break using file:line"
+
+# We'd like this to work, but it currently does not.
+# gdb_test "break one/thefile.cc:$l1"
+
+gdb_test "break dupname" \
+ "Breakpoint 2 at $hex: dupname. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name"
+
+gdb_test "break dupname:label" \
+ "Breakpoint 3 at $hex: dupname:label. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name and label"
+
+gdb_test_no_output "set breakpoint pending off" \
+ "disable pending breakpoints for linespec tests"
+
+# This is PR breakpoints/12856.
+gdb_test "break lspec.cc:nosuchfunction" \
+ "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
+ "set breakpoint on non-existent function"
+
+gdb_test "break NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
+ "set breakpoint at all instances of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at lspec.cc instance of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload(double)" \
+ "Function \"NameSpace::overload\\(double\\)\" not defined in \"lspec.cc\"." \
+ "set breakpoint at non-existent lspec.cc instance of NameSpace::overload"
+
+gdb_test "break NameSpace::overload()" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at specific instance of NameSpace::overload"
+
+#
+# Multi-inferior tests.
+#
+
+gdb_test "add-inferior" "Added inferior 2" \
+ "add inferior for linespec tests"
+
+gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch to inferior 2 for linespec tests"
+
+# Note that in particular this should not cause errors when re-setting
+# breakpoints.
+gdb_test "file $binfile" \
+ "Reading symbols from .*done." \
+ "set the new inferior file for linespec tests"
+
+gdb_test "break main" \
+ "Breakpoint \[0-9\]+ at $hex: main. .2 locations." \
+ "set breakpoint at main in both inferiors"
diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc
new file mode 100644
index 0000000..42e382f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.cc
@@ -0,0 +1,13 @@
+#include "lspec.h"
+
+static int dupname (int x) { label: return x; }
+
+int NameSpace::overload()
+{
+ return 23;
+}
+
+int main()
+{
+ return dupname(0) + m(0) + n(0);
+}
diff --git a/gdb/testsuite/gdb.linespec/lspec.h b/gdb/testsuite/gdb.linespec/lspec.h
new file mode 100644
index 0000000..e4bfc00
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.h
@@ -0,0 +1,9 @@
+extern int m(int x);
+extern int n(int y);
+
+namespace NameSpace {
+ int overload ();
+ int overload (int);
+ int overload (double);
+};
+
diff --git a/gdb/testsuite/gdb.objc/objcdecode.exp b/gdb/testsuite/gdb.objc/objcdecode.exp
index 720bfd8..e3916f6 100644
--- a/gdb/testsuite/gdb.objc/objcdecode.exp
+++ b/gdb/testsuite/gdb.objc/objcdecode.exp
@@ -52,17 +52,19 @@ proc do_objc_tests {} {
do_objc_tests
+gdb_test_no_output "set multiple-symbols ask"
+
#
# Break on multiply defined method (PR objc/1236)
#
set name "break on multiply defined method"
gdb_test_multiple "break multipleDef" $name \
{
- -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] -.Decode multipleDef. at .*\r\n\\\[3\\\] multipleDef at .*\r\n> $" {
+ -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] .*${srcfile}:-.Decode multipleDef.\r\n\\\[3\\\] .*${srcfile}:multipleDef\r\n> $" {
send_gdb "3\n"
exp_continue
}
- -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*\r\n$gdb_prompt $" { pass $name }
+ -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: .*\r\n$gdb_prompt $" { pass $name }
-re ".*$gdb_prompt $" { kfail "gdb/1236" $name }
}
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 679cc32..89a2e24 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -74,6 +74,7 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline2" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
+gdb_test_no_output "set breakpoint pending off"
gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
@@ -81,7 +82,6 @@ gdb_test "info trace" "No tracepoints.*" \
# 1.3 trace line in invalid source file
gdb_delete_tracepoints
-gdb_test_no_output "set breakpoint pending off"
gdb_test "trace NoSuChFiLe.c:1" "No source file named NoSuChFiLe.c." \
"1.3a: trace invalid source file"
gdb_test "info trace" "No tracepoints.*" \
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 4ca4ec2..be38d09 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2437,7 +2437,7 @@ scope_info (char *args, int from_tty)
error (_("requires an argument (function, "
"line or *addr) to define a scope"));
- sals = decode_line_1 (&args, 1, NULL, 0, NULL);
+ sals = decode_line_1 (&args, 1, NULL, 0);
if (sals.nelts == 0)
return; /* Presumably decode_line_1 has already warned. */
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 4c8658d..9b936e1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -455,29 +455,34 @@ tui_update_breakpoint_info (struct tui_win_info *win,
bp != (struct breakpoint *) NULL;
bp = bp->next)
{
+ struct bp_location *loc;
+
gdb_assert (line->line_or_addr.loa == LOA_LINE
|| line->line_or_addr.loa == LOA_ADDRESS);
- if ((win == TUI_SRC_WIN
- && bp->source_file
- && (filename_cmp (src->filename, bp->source_file) == 0)
- && line->line_or_addr.loa == LOA_LINE
- && bp->line_number == line->line_or_addr.u.line_no)
- || (win == TUI_DISASM_WIN
- && line->line_or_addr.loa == LOA_ADDRESS
- && bp->loc != NULL
- && bp->loc->address == line->line_or_addr.u.addr))
- {
- if (bp->enable_state == bp_disabled)
- mode |= TUI_BP_DISABLED;
- else
- mode |= TUI_BP_ENABLED;
- if (bp->hit_count)
- mode |= TUI_BP_HIT;
- if (bp->loc->cond)
- mode |= TUI_BP_CONDITIONAL;
- if (bp->type == bp_hardware_breakpoint)
- mode |= TUI_BP_HARDWARE;
- }
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && loc->source_file
+ && (filename_cmp (src->filename, loc->source_file) == 0)
+ && line->line_or_addr.loa == LOA_LINE
+ && loc->line_number == line->line_or_addr.u.line_no)
+ || (win == TUI_DISASM_WIN
+ && line->line_or_addr.loa == LOA_ADDRESS
+ && loc->address == line->line_or_addr.u.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->loc->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
}
if (line->has_break != mode)
{
diff --git a/gdb/utils.c b/gdb/utils.c
index 008baac..3bc3f94 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3693,6 +3693,17 @@ compare_positive_ints (const void *ap, const void *bp)
return * (int *) ap - * (int *) bp;
}
+/* String compare function for qsort. */
+
+int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+
+ return strcmp (*s1, *s2);
+}
+
#define AMBIGUOUS_MESS1 ".\nMatching formats:"
#define AMBIGUOUS_MESS2 \
".\nUse \"set gnutarget format-name\" to specify the format."
--
1.7.6.4
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:04 ` Tom Tromey
@ 2011-11-14 21:32 ` Jerome Guitton
0 siblings, 0 replies; 42+ messages in thread
From: Jerome Guitton @ 2011-11-14 21:32 UTC (permalink / raw)
To: Tom Tromey; +Cc: Joel Brobecker, Jan Kratochvil, gdb-patches, Paul Hilfinger
Tom Tromey (tromey@redhat.com):
> Yeah, this is actually what happens in multiple-symbols=ask mode: we
> present the canonical forms to the user, and record as the filter the
> one that he chooses.
>
> An implication of this is that we don't discriminate more finely than
> what can be encoded in the canonical form. So, for example, one cannot
> set a symbolic (as opposed to by-address) breakpoint at a single point
> of inlining -- because the canonical form for the inlined function will
> be identical across inlined instances.
>
> I don't know if that description makes any sense outside my head :)
That makes sense in my head as well :) and it think that it is
reasonable. If the "ask" mode discriminated between all points of
inlining, that would most probably make it painful on many optimized
applications.
That is too say: making it asking too many questions would be a
problem. Discriminating at the level of the canonical form seems to
be a good compromise.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
@ 2011-11-15 16:30 ` Tom Tromey
2011-11-15 16:59 ` Pierre Muller
` (2 more replies)
2011-11-16 2:28 ` Yao Qi
` (4 subsequent siblings)
5 siblings, 3 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-15 16:30 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> I plan to commit this sometime this week, barring objections or
Tom> comments; after the doc patch (forthcoming) is approved.
I'm having second thoughts about this. Today it seems slightly crazy to
check in such a huge patch just before a release. Any other thoughts on
this?
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* RE: RFA: implement ambiguous linespec proposal
2011-11-15 16:30 ` Tom Tromey
@ 2011-11-15 16:59 ` Pierre Muller
2011-11-16 0:09 ` Jan Kratochvil
2011-11-16 21:23 ` Stan Shebs
2 siblings, 0 replies; 42+ messages in thread
From: Pierre Muller @ 2011-11-15 16:59 UTC (permalink / raw)
To: 'Tom Tromey', 'Jan Kratochvil'; +Cc: gdb-patches
> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Tom Tromey
> Envoyé : mardi 15 novembre 2011 17:30
> À : Jan Kratochvil
> Cc : gdb-patches@sourceware.org
> Objet : Re: RFA: implement ambiguous linespec proposal
>
> >>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>
> Tom> I plan to commit this sometime this week, barring objections or
> Tom> comments; after the doc patch (forthcoming) is approved.
>
> I'm having second thoughts about this. Today it seems slightly crazy to
> check in such a huge patch just before a release. Any other thoughts on
> this?
Even though I understand your hesitations,
I want to say that, for pascal language support, your patch is a
huge step forward:
With it I can finally set a breakpoint to both version of ASSIGN
system unit procedure simply by using
(gdb) break ASSIGN
I do get two locations, in two different include files,
which is really great!
Without your patch, I only get whatever GDB finds first...
Thus, I vote for commit ASAP.
Pierre Muller
Pascal language maintainer
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-15 16:30 ` Tom Tromey
2011-11-15 16:59 ` Pierre Muller
@ 2011-11-16 0:09 ` Jan Kratochvil
2011-11-16 1:58 ` Joel Brobecker
2011-11-16 14:46 ` Tom Tromey
2011-11-16 21:23 ` Stan Shebs
2 siblings, 2 replies; 42+ messages in thread
From: Jan Kratochvil @ 2011-11-16 0:09 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Tue, 15 Nov 2011 17:30:18 +0100, Tom Tromey wrote:
> I'm having second thoughts about this. Today it seems slightly crazy to
> check in such a huge patch just before a release. Any other thoughts on
> this?
Maybe to formalize more the GDB releng process? I thought before branching
any development is valid - like stage1 of GCC.
Still more time could give more reviews, for whatever reason I for example
haven't yet run a regression test on `break'ing on all symbols of Fedora
.debug files which found regressions in Keith's patchset, also I haven't yet
found energy for the full review for whatever reason. But it is also true it
would miss 7.4 that way and the patch benefits look to be worth possible minor
regressions. Just FYI my $0.02 as I was in To.
Thanks,
Jan
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 0:09 ` Jan Kratochvil
@ 2011-11-16 1:58 ` Joel Brobecker
2011-11-16 14:46 ` Tom Tromey
1 sibling, 0 replies; 42+ messages in thread
From: Joel Brobecker @ 2011-11-16 1:58 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches
> > I'm having second thoughts about this. Today it seems slightly crazy to
> > check in such a huge patch just before a release. Any other thoughts on
> > this?
>
> Maybe to formalize more the GDB releng process? I thought before branching
> any development is valid - like stage1 of GCC.
IMO, it is (allowed). A little bit of stabilization before the branch
would be nice, but we have the branch to do any stabilization, if
required.
That being said, if the patch is huge and touches a sensitive part of
the debugger, we might be setting ourselves up for another situation
similar to what we got with the physname patch.
So, I'm personally 50-50 on this. If we want to compromise, we can
branch 7.4 without this patch, but start 7.5 shortly after (within
a few weeks, or a month after). I agree with Pierre that this is
a very nice improvement, so we should try to get it out in a release
sooner rather than later.
--
Joel
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
2011-11-15 16:30 ` Tom Tromey
@ 2011-11-16 2:28 ` Yao Qi
2011-11-16 3:20 ` Doug Evans
2011-11-16 14:46 ` Tom Tromey
2011-11-16 4:57 ` Doug Evans
` (3 subsequent siblings)
5 siblings, 2 replies; 42+ messages in thread
From: Yao Qi @ 2011-11-16 2:28 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 11/15/2011 05:10 AM, Tom Tromey wrote:
> Here is the final revision.
>
> I plan to commit this sometime this week, barring objections or
> comments; after the doc patch (forthcoming) is approved.
Tom,
I tried to apply this patch to FSF trunk, but there are some conflicts
in breakpoint.c, valprint.c and symtab.c. Conflicts in the first two
files are trivial to me, but conflict in symtab.c isn't. I noticed Jan
and Pierre must have applied this patch, but I wonder how that happen.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 2:28 ` Yao Qi
@ 2011-11-16 3:20 ` Doug Evans
2011-11-16 14:46 ` Tom Tromey
1 sibling, 0 replies; 42+ messages in thread
From: Doug Evans @ 2011-11-16 3:20 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
On Tue, Nov 15, 2011 at 6:28 PM, Yao Qi <yao@codesourcery.com> wrote:
> On 11/15/2011 05:10 AM, Tom Tromey wrote:
>> Here is the final revision.
>>
>> I plan to commit this sometime this week, barring objections or
>> comments; after the doc patch (forthcoming) is approved.
>
> Tom,
> I tried to apply this patch to FSF trunk, but there are some conflicts
> in breakpoint.c, valprint.c and symtab.c. Conflicts in the first two
> files are trivial to me, but conflict in symtab.c isn't. I noticed Jan
> and Pierre must have applied this patch, but I wonder how that happen.
Yeah, I tried to apply it too.
I want to see if it helps with how I should approach some performance
concerns (short of a symbol table rewrite).
It applies ok if you check out the tree when Tom made the patch, 2011-11-10.
E.g., cvs co -D2011-11-10 gdb
But then you miss out on some recent changes of course.
I'm all for getting this into 7.4 btw.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
2011-11-15 16:30 ` Tom Tromey
2011-11-16 2:28 ` Yao Qi
@ 2011-11-16 4:57 ` Doug Evans
2011-11-16 5:22 ` Doug Evans
2011-11-16 14:49 ` Tom Tromey
2011-11-16 8:15 ` Yao Qi
` (2 subsequent siblings)
5 siblings, 2 replies; 42+ messages in thread
From: Doug Evans @ 2011-11-16 4:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On Mon, Nov 14, 2011 at 1:10 PM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>
> Tom> Here is a refresh of this patch. This fixes the regressions noted by
> Tom> Jan, but also changes ovsrch.exp not to assume that namespace lookups
> Tom> are done.
>
> Here is the final revision.
While your patch didn't introduce the this, I'm wondering if you have
thoughts on this.
Single vs double quote handling in linespecs is, umm, odd.
[It's probably seems odder than it really is due to poor naming,
"quote" is just too ambiguous. At some point I'd like to enforce
"squote" and "dquote" instead of just "quote" when only one is meant.
:-)]
E.g.,
decode_line_internal has this:
is_quoted = (strchr (get_gdb_completer_quote_characters (),
**argptr) != NULL);
if (is_quoted) //xxx quoted? what kind of quoted?
{
end_quote = skip_quoted (*argptr);
if (*end_quote == '\0')
is_squote_enclosed = 1; //xxx
}
xxx: We're hardcoding knowledge that
get_gdb_completer_quote_characters (emphasis on the plural!) is
actually just the single quote '.
linespec.c:symtabs_from_filename has this:
/* It may have the ending quote right after the file name. */
if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
|| copy[p - *argptr - 1] == '\'')
copy[p - *argptr - 1] = 0;
Why is ' and " treated differently?
[I realize the comment for gdb_completer_quote_characters says why
*it* doesn't include dquote("), but I'd rather not use it if it makes
for clearer code.]
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 4:57 ` Doug Evans
@ 2011-11-16 5:22 ` Doug Evans
2011-11-16 14:54 ` Tom Tromey
2011-11-16 14:49 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Doug Evans @ 2011-11-16 5:22 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On Tue, Nov 15, 2011 at 8:57 PM, Doug Evans <dje@google.com> wrote:
> On Mon, Nov 14, 2011 at 1:10 PM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>>
>> Tom> Here is a refresh of this patch. This fixes the regressions noted by
>> Tom> Jan, but also changes ovsrch.exp not to assume that namespace lookups
>> Tom> are done.
>>
>> Here is the final revision.
Another question while we're cleaning up linespecs, if I may.
The docs have this:
@item '@var{filename}'::@var{funcaddr}
Like @var{funcaddr} above, but also specifies the name of the source
file explicitly. This is useful if the name of the function does not
specify the function unambiguously, e.g., if there are several
functions with identical names in different source files.
Is the double colon, ::, a typo? I've only ever seen filename
delimited with a single colon.
I'm hoping we can trivially decide that a file name is present by
seeing a single colon.
[First trying "foo" in "foo::bar" as file, only afterwards to try it
as a class or a namespace if that fails is clumsy, and a perf issue.]
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
` (2 preceding siblings ...)
2011-11-16 4:57 ` Doug Evans
@ 2011-11-16 8:15 ` Yao Qi
2011-11-16 16:17 ` Tom Tromey
2011-11-16 15:43 ` Yao Qi
2011-11-23 21:33 ` Tom Tromey
5 siblings, 1 reply; 42+ messages in thread
From: Yao Qi @ 2011-11-16 8:15 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 11/15/2011 05:10 AM, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
>
> Tom> Here is a refresh of this patch. This fixes the regressions noted by
> Tom> Jan, but also changes ovsrch.exp not to assume that namespace lookups
> Tom> are done.
>
> Here is the final revision.
>
> I plan to commit this sometime this week, barring objections or
> comments; after the doc patch (forthcoming) is approved.
>
Thanks to Doug, I applied your patch on GDB CVS 2011-11-10. My comments
below,
>
> @@ -7579,15 +7438,20 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
>
> for (i = 0; i < sals->nelts; i++)
> {
> + struct gdbarch *sarch;
> +
> sal = &sals->sals[i];
>
> - rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
> + sarch = get_sal_arch (*sal);
I suggest that we add a comment, I steal from Ulrich's comment :)
/* We fall back to GDBARCH if there is no architecture
associated with SAL. */
> + if (sarch == NULL)
> + sarch = gdbarch;
> + rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
> NULL, &msg);
> old_chain = make_cleanup (xfree, msg);
>
> if (!rslt)
> error (_("May not have a fast tracepoint at 0x%s%s"),
> - paddress (gdbarch, sal->pc), (msg ? msg : ""));
> + paddress (sarch, sal->pc), (msg ? msg : ""));
>
> do_cleanups (old_chain);
> }
> @@ -7729,8 +7593,6 @@ create_breakpoint (struct gdbarch *gdbarch,
> int from_tty, int enabled, int internal)
> {
> volatile struct gdb_exception e;
> - struct symtabs_and_lines sals;
> - struct symtab_and_line pending_sal;
> char *copy_arg;
I got a compilation warning below, and looks like copy_arg should be
initialized to NULL.
gdb/breakpoint.c:7636: error: 'copy_arg' may be used uninitialized
in this functiongdb/breakpoint.c:7636: error: 'copy_arg' may be used
uninitialized in this function
> char *addr_start = arg;
> struct linespec_result canonical;
> @@ -7743,26 +7605,26 @@ create_breakpoint (struct gdbarch *gdbarch,
>
> gdb_assert (ops != NULL);
>
> - sals.sals = NULL;
> - sals.nelts = 0;
> init_linespec_result (&canonical);
>
> if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
> {
> int i;
> + struct linespec_sals lsal;
>
> - sals = decode_static_tracepoint_spec (&arg);
> + lsal.sals = decode_static_tracepoint_spec (&arg);
>
> copy_arg = savestring (addr_start, arg - addr_start);
> - canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
> - for (i = 0; i < sals.nelts; i++)
> - canonical.canonical[i] = xstrdup (copy_arg);
> +
> + lsal.canonical = xstrdup (copy_arg);
> + VEC_safe_push (linespec_sals, canonical.sals, &lsal);
> +
> goto done;
> }
>
> TRY_CATCH (e, RETURN_MASK_ALL)
> {
> - parse_breakpoint_sals (&arg, &sals, &canonical);
> + parse_breakpoint_sals (&arg, &canonical);
> }
>
> /* If caller is interested in rc value from parse, set value. */
> @@ -7794,35 +7656,31 @@ create_breakpoint (struct gdbarch *gdbarch,
> a pending breakpoint and selected yes, or pending
> breakpoint behavior is on and thus a pending breakpoint
> is defaulted on behalf of the user. */
> - copy_arg = xstrdup (addr_start);
> - canonical.canonical = ©_arg;
> - sals.nelts = 1;
> - sals.sals = &pending_sal;
> - pending_sal.pc = 0;
> - pending = 1;
> + {
> + struct linespec_sals lsal;
> +
> + copy_arg = xstrdup (addr_start);
> + lsal.canonical = xstrdup (copy_arg);
> + lsal.sals.nelts = 1;
> + lsal.sals.sals = XNEW (struct symtab_and_line);
> + init_sal (&lsal.sals.sals[0]);
> + pending = 1;
> + VEC_safe_push (linespec_sals, canonical.sals, &lsal);
> + }
> break;
> default:
> throw_exception (e);
> }
> break;
> default:
> - if (!sals.nelts)
> + if (VEC_empty (linespec_sals, canonical.sals))
> return 0;
> }
>
> done:
>
> /* Create a chain of things that always need to be cleaned up. */
> - old_chain = make_cleanup (null_cleanup, 0);
> -
> - if (!pending)
> - {
> - /* Make sure that all storage allocated to SALS gets freed. */
> - make_cleanup (xfree, sals.sals);
> -
> - /* Cleanup the canonical array but not its contents. */
> - make_cleanup (xfree, canonical.canonical);
> - }
> + old_chain = make_cleanup_destroy_linespec_result (&canonical);
>
> /* ----------------------------- SNIP -----------------------------
> Anything added to the cleanup chain beyond this point is assumed
> @@ -7830,28 +7688,36 @@ create_breakpoint (struct gdbarch *gdbarch,
> then the memory is not reclaimed. */
> bkpt_chain = make_cleanup (null_cleanup, 0);
>
> - /* Mark the contents of the canonical for cleanup. These go on
> - the bkpt_chain and only occur if the breakpoint create fails. */
> - for (i = 0; i < sals.nelts; i++)
> - {
> - if (canonical.canonical[i] != NULL)
> - make_cleanup (xfree, canonical.canonical[i]);
> - }
> -
> /* Resolve all line numbers to PC's and verify that the addresses
> are ok for the target. */
> if (!pending)
> - breakpoint_sals_to_pc (&sals);
> + {
> + int ix;
> + struct linespec_sals *iter;
> +
> + for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
> + breakpoint_sals_to_pc (&iter->sals);
> + }
>
> /* Fast tracepoints may have additional restrictions on location. */
> if (type_wanted == bp_fast_tracepoint)
> - check_fast_tracepoint_sals (gdbarch, &sals);
> + {
> + int ix;
> + struct linespec_sals *iter;
> +
> + for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
> + check_fast_tracepoint_sals (gdbarch, &iter->sals);
> + }
>
> /* Verify that condition can be parsed, before setting any
> breakpoints. Allocate a separate condition expression for each
> breakpoint. */
> if (!pending)
> {
> + struct linespec_sals *lsal;
> +
> + lsal = VEC_index (linespec_sals, canonical.sals, 0);
> +
> if (parse_condition_and_thread)
> {
> /* Here we only parse 'arg' to separate condition
> @@ -7860,7 +7726,7 @@ create_breakpoint (struct gdbarch *gdbarch,
> re-parse it in context of each sal. */
> cond_string = NULL;
> thread = -1;
> - find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
> + find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
> &thread, &task);
> if (cond_string)
> make_cleanup (xfree, cond_string);
> @@ -7882,24 +7748,26 @@ create_breakpoint (struct gdbarch *gdbarch,
> expand multiple locations for each sal, given than SALS
> already should contain all sals for MARKER_ID. */
> if (type_wanted == bp_static_tracepoint
> - && is_marker_spec (canonical.canonical[0]))
> + && is_marker_spec (lsal->canonical))
> {
> int i;
>
> - for (i = 0; i < sals.nelts; ++i)
> + for (i = 0; i < lsal->sals.nelts; ++i)
> {
> struct symtabs_and_lines expanded;
> struct tracepoint *tp;
> struct cleanup *old_chain;
> + char *addr_string;
>
> expanded.nelts = 1;
> - expanded.sals = xmalloc (sizeof (struct symtab_and_line));
> - expanded.sals[0] = sals.sals[i];
> - old_chain = make_cleanup (xfree, expanded.sals);
> + expanded.sals = &lsal->sals.sals[i];
> +
> + addr_string = xstrdup (canonical.addr_string);
> + old_chain = make_cleanup (xfree, addr_string);
>
> tp = XCNEW (struct tracepoint);
> init_breakpoint_sal (&tp->base, gdbarch, expanded,
> - canonical.canonical[i],
> + addr_string, NULL,
> cond_string, type_wanted,
> tempflag ? disp_del : disp_donttouch,
> thread, task, ignore_count, ops,
> @@ -11619,8 +11488,17 @@ update_breakpoint_locations (struct breakpoint *b,
> int i;
> struct bp_location *existing_locations = b->loc;
>
> - /* Ranged breakpoints have only one start location and one end location. */
> - gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
> + if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
> + {
> + /* Ranged breakpoints have only one start location and one end
> + location. */
> + b->enable_state = bp_disabled;
> + update_global_location_list (1);
> + printf_unfiltered (_("Could not reset ranged breakpoint %d: "
> + "multiple locations found\n"),
> + b->number);
> + return;
> + }
>
I don't understand why assert is replaced by a condition check.
Could you elaborate a little?
> /* If there's no new locations, and all existing locations are
> pending, don't do anything. This optimizes the common case where
> @@ -11635,8 +11513,11 @@ update_breakpoint_locations (struct breakpoint *b,
>
> for (i = 0; i < sals.nelts; ++i)
> {
> - struct bp_location *new_loc =
> - add_location_to_breakpoint (b, &(sals.sals[i]));
> + struct bp_location *new_loc;
> +
> + switch_to_program_space_and_thread (sals.sals[i].pspace);
> +
> + new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
>
> /* Reparse conditions, they might contain references to the
> old symtab. */
> @@ -11660,16 +11541,6 @@ update_breakpoint_locations (struct breakpoint *b,
> }
> }
>
> - if (b->source_file != NULL)
> - xfree (b->source_file);
> - if (sals.sals[i].symtab == NULL)
> - b->source_file = NULL;
> - else
> - b->source_file = xstrdup (sals.sals[i].symtab->filename);
> -
> - if (b->line_number == 0)
> - b->line_number = sals.sals[i].line;
> -
> if (sals_end.nelts)
> {
> CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
> diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
> new file mode 100644
> index 0000000..122a468
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/linespec.exp
> @@ -0,0 +1,106 @@
> +# Copyright 2011 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +# Tests of ambiguous linespecs.
> +
> +set testfile linespec
> +
> +set exefile lspec
> +set binfile ${objdir}/${subdir}/${exefile}
> +
> +set baseone base/one/thefile.cc
> +set basetwo base/two/thefile.cc
> +
> +set hex {0x[0-9a-fA-F]+}
> +
${hex} has been defined in dejagnu/runtest.exp, and we can simply
use it.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 0:09 ` Jan Kratochvil
2011-11-16 1:58 ` Joel Brobecker
@ 2011-11-16 14:46 ` Tom Tromey
2011-11-18 14:10 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 14:46 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
Jan> Still more time could give more reviews, for whatever reason I for
Jan> example haven't yet run a regression test on `break'ing on all
Jan> symbols of Fedora .debug files which found regressions in Keith's
Jan> patchset, also I haven't yet found energy for the full review for
Jan> whatever reason.
I'll try this test against the debuginfo I have installed here.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 2:28 ` Yao Qi
2011-11-16 3:20 ` Doug Evans
@ 2011-11-16 14:46 ` Tom Tromey
2011-11-16 16:06 ` Tom Tromey
1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 14:46 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
Yao> I tried to apply this patch to FSF trunk, but there are some conflicts
Yao> in breakpoint.c, valprint.c and symtab.c. Conflicts in the first two
Yao> files are trivial to me, but conflict in symtab.c isn't. I noticed Jan
Yao> and Pierre must have applied this patch, but I wonder how that happen.
I'll rebase it today and send out a new patch.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 4:57 ` Doug Evans
2011-11-16 5:22 ` Doug Evans
@ 2011-11-16 14:49 ` Tom Tromey
1 sibling, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 14:49 UTC (permalink / raw)
To: Doug Evans; +Cc: Jan Kratochvil, gdb-patches
>>>>> "Doug" == Doug Evans <dje@google.com> writes:
Doug> Single vs double quote handling in linespecs is, umm, odd.
Doug> [It's probably seems odder than it really is due to poor naming,
Doug> "quote" is just too ambiguous. At some point I'd like to enforce
Doug> "squote" and "dquote" instead of just "quote" when only one is meant.
Doug> :-)]
Keith is working on this. He's replacing the current distributed, ad
hoc lexing code in linespec.c with something more centralized and
uniform. This should let us more easily add new kinds of linespecs,
like "FILE:FUNCTION:LINE" or "OBJFILE:FILE:FUNCTION" without making all
the code even more horrible.
I don't have insight into the specific case of different quoting styles.
You can see Keith's work-in-progress on archer-keiths-linespec-parser.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 5:22 ` Doug Evans
@ 2011-11-16 14:54 ` Tom Tromey
2011-11-16 16:32 ` Doug Evans
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 14:54 UTC (permalink / raw)
To: Doug Evans; +Cc: Jan Kratochvil, gdb-patches
>>>>> "Doug" == Doug Evans <dje@google.com> writes:
Doug> Another question while we're cleaning up linespecs, if I may.
Doug> The docs have this:
Doug> @item '@var{filename}'::@var{funcaddr}
Doug> Like @var{funcaddr} above, but also specifies the name of the source
Doug> file explicitly. This is useful if the name of the function does not
Doug> specify the function unambiguously, e.g., if there are several
Doug> functions with identical names in different source files.
Doug> Is the double colon, ::, a typo? I've only ever seen filename
Doug> delimited with a single colon.
This form is only valid for expressions, that is, if you type
break *'file.c'::function
This is a syntax extension that gdb provides. See the 'block'
production in c-exp.y.
Doug> I'm hoping we can trivially decide that a file name is present by
Doug> seeing a single colon.
In general I agree, but there are some corner cases to consider.
There's the easy(-ish) corner case of DOS file names:
break c:/file.c:function
There's also an Objective C case where a trailing ":" is part of the
function name. I forget the exact syntax, maybe it can only appear in
brackets:
break +[method:]
Anyway, like I said in the previous thread, in my view, gdb should
require quoting for all unusual file names. We should try to be
compatible, but we don't have to try too awfully hard, since a lot of
things never worked anyway.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
` (3 preceding siblings ...)
2011-11-16 8:15 ` Yao Qi
@ 2011-11-16 15:43 ` Yao Qi
2011-11-16 16:11 ` Tom Tromey
2011-11-23 21:33 ` Tom Tromey
5 siblings, 1 reply; 42+ messages in thread
From: Yao Qi @ 2011-11-16 15:43 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On 11/15/2011 05:10 AM, Tom Tromey wrote:
> Tom> Here is a refresh of this patch. This fixes the regressions noted by
> Tom> Jan, but also changes ovsrch.exp not to assume that namespace lookups
> Tom> are done.
>
> Here is the final revision.
Tom,
I applied it to GDB CVS 2011-11-10, and run regression test on
tic6x-uclinux. There are two new fails,
-PASS: gdb.cp/ovsrch.exp: break outer::foo if (a == 3)
+FAIL: gdb.cp/ovsrch.exp: break A::outer::foo if (a == 3)
-PASS: gdb.cp/ovsrch.exp: break inner::foo if (a == 3)
+FAIL: gdb.cp/ovsrch.exp: break A::B::inner::foo if (a == 3)
break A::outer::foo if (a == 3)^M
Note: breakpoints 4, 5, 6, 7, 8 and 9 also set at pc 0xe79e2434.^M
Note: breakpoints 12, 13, 14, 15, 16 and 17 also set at pc 0xe79e23d4.^M
Note: breakpoints 10 and 11 also set at pc 0xe79e2370.^M
No symbol "a" in current context.^M
(gdb) FAIL: gdb.cp/ovsrch.exp: break A::outer::foo if (a == 3)
break A::B::inner::foo if (a == 3)^M
Note: breakpoints 20, 21, 22, 23, 24 and 25 also set at pc 0xe79e245c.^M
Note: breakpoints 28, 29, 30, 31, 32 and 33 also set at pc 0xe79e23fc.^M
Note: breakpoints 26 and 27 also set at pc 0xe79e2394.^M
No symbol "a" in current context.^M
(gdb) FAIL: gdb.cp/ovsrch.exp: break A::B::inner::foo if (a == 3)
I'll debug this problem tomorrow, but if you have any clues, that will
be helpful.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 14:46 ` Tom Tromey
@ 2011-11-16 16:06 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 16:06 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 348 bytes --]
>>>>> "Yao" == Tom Tromey <tromey@redhat.com> writes:
Tom> I'll rebase it today and send out a new patch.
Here are the new patches. I rebased these onto trunk as of this
morning.
Built and regtested on x86-64 F15. This showed a kfail->kpass
transition that I missed earlier, so I updated the patch and added
another PR to the ChangeLog.
Tom
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: remove bp_startup_disabled --]
[-- Type: text/x-patch, Size: 5862 bytes --]
From ee180d596d8610b4554ea76839f3a8a6da984a69 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 10 Nov 2011 08:55:34 -0700
Subject: [PATCH 1/4] remove bp_startup_disabled
---
gdb/ChangeLog | 14 +++++++++++
gdb/breakpoint.c | 67 ++++++-----------------------------------------------
gdb/breakpoint.h | 8 ------
3 files changed, 22 insertions(+), 67 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 1f406fa..431256a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@
+2011-11-16 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.
+
2011-11-15 Doug Evans <dje@google.com>
* buildsym.c (add_symbol_to_list): Delete outdated comment.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8f09296..2494520 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1574,6 +1574,9 @@ should_be_inserted (struct bp_location *bl)
if (!bl->enabled || bl->shlib_disabled || bl->duplicate)
return 0;
+ if (user_breakpoint_p (bl->owner) && bl->pspace->executing_startup)
+ return 0;
+
/* This is set for example, when we're attached to the parent of a
vfork, and have detached from the child. The child is running
free, and we expect it to do an exec or exit, at which point the
@@ -5314,8 +5317,7 @@ describe_other_breakpoints (struct gdbarch *gdbarch,
printf_filtered (" (thread %d)", b->thread);
printf_filtered ("%s%s ",
((b->enable_state == bp_disabled
- || b->enable_state == bp_call_disabled
- || b->enable_state == bp_startup_disabled)
+ || b->enable_state == bp_call_disabled)
? " (disabled)"
: b->enable_state == bp_permanent
? " (permanent)"
@@ -6930,53 +6932,15 @@ enable_watchpoints_after_interactive_call_stop (void)
void
disable_breakpoints_before_startup (void)
{
- struct breakpoint *b;
- int found = 0;
-
- ALL_BREAKPOINTS (b)
- {
- if (b->pspace != current_program_space)
- continue;
-
- if ((b->type == bp_breakpoint
- || b->type == bp_hardware_breakpoint)
- && breakpoint_enabled (b))
- {
- b->enable_state = bp_startup_disabled;
- found = 1;
- }
- }
-
- if (found)
- update_global_location_list (0);
-
current_program_space->executing_startup = 1;
+ update_global_location_list (0);
}
void
enable_breakpoints_after_startup (void)
{
- struct breakpoint *b;
- int found = 0;
-
current_program_space->executing_startup = 0;
-
- ALL_BREAKPOINTS (b)
- {
- if (b->pspace != current_program_space)
- continue;
-
- if ((b->type == bp_breakpoint
- || b->type == bp_hardware_breakpoint)
- && b->enable_state == bp_startup_disabled)
- {
- b->enable_state = bp_enabled;
- found = 1;
- }
- }
-
- if (found)
- breakpoint_re_set ();
+ breakpoint_re_set ();
}
@@ -7264,11 +7228,6 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
"tracepoint marker to probe"));
}
- if (enabled && b->pspace->executing_startup
- && (b->type == bp_breakpoint
- || b->type == bp_hardware_breakpoint))
- b->enable_state = bp_startup_disabled;
-
loc = b->loc;
}
else
@@ -7991,11 +7950,6 @@ create_breakpoint (struct gdbarch *gdbarch,
b->pspace = current_program_space;
b->py_bp_object = NULL;
- if (enabled && b->pspace->executing_startup
- && (b->type == bp_breakpoint
- || b->type == bp_hardware_breakpoint))
- b->enable_state = bp_startup_disabled;
-
if (!internal)
/* Do not mention breakpoints with a negative number,
but do notify observers. */
@@ -10664,11 +10618,7 @@ update_global_location_list (int should_insert)
struct breakpoint *b = loc->owner;
struct bp_location **loc_first_p;
- if (b->enable_state == bp_disabled
- || b->enable_state == bp_call_disabled
- || b->enable_state == bp_startup_disabled
- || !loc->enabled
- || loc->shlib_disabled
+ if (!should_be_inserted (loc)
|| !breakpoint_address_is_meaningful (b)
/* Don't detect duplicate for tracepoint locations because they are
never duplicated. See the comments in field `duplicate' of
@@ -10954,8 +10904,7 @@ static struct breakpoint_ops base_breakpoint_ops =
static void
bkpt_re_set (struct breakpoint *b)
{
- /* Do not attempt to re-set breakpoints disabled during startup. */
- if (b->enable_state == bp_startup_disabled)
+ if (current_program_space->executing_startup)
return;
/* FIXME: is this still reachable? */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 506ae80..7a8b4de 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -186,14 +186,6 @@ enum enable_state
automatically enabled and reset when the
call "lands" (either completes, or stops
at another eventpoint). */
- bp_startup_disabled, /* The eventpoint has been disabled during
- inferior startup. This is necessary on
- some targets where the main executable
- will get relocated during startup, making
- breakpoint addresses invalid. The
- eventpoint will be automatically enabled
- and reset once inferior startup is
- complete. */
bp_permanent /* There is a breakpoint instruction
hard-wired into the target's code. Don't
try to write another breakpoint
--
1.7.6.4
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: make pspace optional --]
[-- Type: text/x-patch, Size: 4695 bytes --]
From 3558b05ff57221e51b69cccd890f274e02e2df9f Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 10 Nov 2011 08:56:39 -0700
Subject: [PATCH 2/4] make pspace optional
---
gdb/ChangeLog | 12 ++++++++++++
gdb/breakpoint.c | 19 ++++++++++---------
gdb/breakpoint.h | 4 +++-
gdb/elfread.c | 2 +-
4 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 431256a..7bc0370 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
2011-11-16 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-11-16 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.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2494520..66cdfbd 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5792,9 +5792,11 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_catchpoint)
gdb_assert (sal.pspace != NULL);
- /* Store the program space that was used to set the breakpoint, for
- breakpoint resetting. */
- b->pspace = sal.pspace;
+ /* Store the program space that was used to set the breakpoint,
+ except for ordinary breakpoints, which are independent of the
+ program space. */
+ if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
+ b->pspace = sal.pspace;
if (sal.symtab == NULL)
b->source_file = NULL;
@@ -7187,7 +7189,6 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
b->ignore_count = ignore_count;
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = disposition;
- b->pspace = sals.sals[0].pspace;
if (type == bp_static_tracepoint)
{
@@ -7947,7 +7948,8 @@ create_breakpoint (struct gdbarch *gdbarch,
b->disposition = tempflag ? disp_del : disp_donttouch;
b->condition_not_parsed = 1;
b->enable_state = enabled ? bp_enabled : bp_disabled;
- b->pspace = current_program_space;
+ if (type_wanted != bp_breakpoint && type_wanted != bp_hardware_breakpoint)
+ b->pspace = current_program_space;
b->py_bp_object = NULL;
if (!internal)
@@ -10904,9 +10906,6 @@ static struct breakpoint_ops base_breakpoint_ops =
static void
bkpt_re_set (struct breakpoint *b)
{
- if (current_program_space->executing_startup)
- return;
-
/* FIXME: is this still reachable? */
if (b->addr_string == NULL)
{
@@ -11837,6 +11836,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.error == NOT_FOUND_ERROR
&& (b->condition_not_parsed
|| (b->loc && b->loc->shlib_disabled)
+ || (b->loc && b->loc->pspace->executing_startup)
|| b->enable_state == bp_disabled))
not_found_and_ok = 1;
@@ -11925,7 +11925,8 @@ prepare_re_set_context (struct breakpoint *b)
input_radix = b->input_radix;
cleanups = save_current_space_and_thread ();
- switch_to_program_space_and_thread (b->pspace);
+ if (b->pspace != NULL)
+ switch_to_program_space_and_thread (b->pspace);
set_language (b->language);
return cleanups;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a8b4de..9defd02 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -567,7 +567,9 @@ struct breakpoint
equals this. */
struct frame_id frame_id;
- /* The program space used to set the breakpoint. */
+ /* The program space used to set the breakpoint. This is only set
+ for breakpoints which are specific to a program space; for
+ ordinary breakpoints this is NULL. */
struct program_space *pspace;
/* String we used to set the breakpoint (malloc'd). */
diff --git a/gdb/elfread.c b/gdb/elfread.c
index a309a2c..067c77f 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -1032,7 +1032,7 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
}
gdb_assert (b->type == bp_gnu_ifunc_resolver);
- gdb_assert (current_program_space == b->pspace);
+ gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
sal = find_pc_line (resolved_pc, 0);
--
1.7.6.4
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: the rewrite --]
[-- Type: text/x-patch, Size: 237919 bytes --]
From 5c156ed924bf05cc95fa73a1325e43bf6d2770e6 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 27 Oct 2011 09:26:30 -0600
Subject: [PATCH 3/4] the rewrite
---
gdb/ChangeLog | 151 ++
gdb/block.c | 14 +
gdb/block.h | 2 +
gdb/breakpoint.c | 545 +++----
gdb/breakpoint.h | 21 +-
gdb/cli/cli-cmds.c | 103 +-
gdb/defs.h | 1 +
gdb/dwarf2loc.c | 3 -
gdb/dwarf2read.c | 60 +-
gdb/linespec.c | 2489 +++++++++++++++---------
gdb/linespec.h | 105 +-
gdb/minsyms.c | 40 +
gdb/objc-lang.c | 288 +--
gdb/objc-lang.h | 12 +-
gdb/psymtab.c | 80 +-
gdb/python/py-type.c | 14 +-
gdb/python/python.c | 2 +-
gdb/skip.c | 4 +-
gdb/solib-target.c | 2 -
gdb/source.c | 8 +-
gdb/stack.c | 16 +-
gdb/symfile.h | 34 +-
gdb/symtab.c | 371 +++-
gdb/symtab.h | 34 +
gdb/testsuite/ChangeLog | 33 +
gdb/testsuite/Makefile.in | 2 +-
gdb/testsuite/configure | 3 +-
gdb/testsuite/configure.ac | 2 +-
gdb/testsuite/gdb.base/break.exp | 3 +-
gdb/testsuite/gdb.base/list.exp | 2 +-
gdb/testsuite/gdb.base/sepdebug.exp | 3 +-
gdb/testsuite/gdb.base/solib-symbol.exp | 14 +-
gdb/testsuite/gdb.base/solib-weak.exp | 9 -
gdb/testsuite/gdb.cp/mb-ctor.exp | 4 +-
gdb/testsuite/gdb.cp/mb-inline.exp | 4 +-
gdb/testsuite/gdb.cp/mb-templates.exp | 6 +-
gdb/testsuite/gdb.cp/method2.exp | 2 +-
gdb/testsuite/gdb.cp/ovldbreak.exp | 79 +-
gdb/testsuite/gdb.cp/ovsrch.exp | 20 +-
gdb/testsuite/gdb.cp/re-set-overloaded.exp | 1 -
gdb/testsuite/gdb.cp/templates.exp | 9 +-
gdb/testsuite/gdb.linespec/Makefile.in | 14 +
gdb/testsuite/gdb.linespec/base/one/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/base/two/thefile.cc | 19 +
gdb/testsuite/gdb.linespec/linespec.exp | 106 +
gdb/testsuite/gdb.linespec/lspec.cc | 13 +
gdb/testsuite/gdb.linespec/lspec.h | 9 +
gdb/testsuite/gdb.objc/objcdecode.exp | 6 +-
gdb/testsuite/gdb.trace/tracecmd.exp | 2 +-
gdb/tracepoint.c | 2 +-
gdb/tui/tui-winsource.c | 47 +-
gdb/utils.c | 11 +
52 files changed, 3051 insertions(+), 1792 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/Makefile.in
create mode 100644 gdb/testsuite/gdb.linespec/base/one/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/base/two/thefile.cc
create mode 100644 gdb/testsuite/gdb.linespec/linespec.exp
create mode 100644 gdb/testsuite/gdb.linespec/lspec.cc
create mode 100644 gdb/testsuite/gdb.linespec/lspec.h
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7bc0370..7abd7ef 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,156 @@
2011-11-16 Tom Tromey <tromey@redhat.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:
+ * 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.
+ * 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.
+ * 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.
+ (compare_core_addrs, find_pcs_for_symtab_line): New functions.
+ (find_line_common): Add 'start' argument.
+ (decode_line_spec): Update.
+ * 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.
+ * source.c (line_info): Set pspace on sal. Check program space in
+ the loop.
+ * 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 (struct linespec_sals): New type.
+ (struct linespec_result) <canonical>: Remove.
+ <pre_expanded, addr_string, sals>: New fields.
+ (destroy_linespec_result, make_cleanup_destroy_linespec_result)
+ (decode_line_list, 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, decode_line_list): 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. Fall back on
+ decode_variable.
+ (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.
+ * 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. 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.
+ (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.
+ * block.h (block_containing_function): Declare.
+ * block.c (block_containing_function): New function.
+ * skip.c (skip_function_command): Update.
+ (skip_re_set): Update.
+
+2011-10-28 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.
diff --git a/gdb/block.c b/gdb/block.c
index c165bc2..1fa3688 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -82,6 +82,20 @@ block_linkage_function (const struct block *bl)
return BLOCK_FUNCTION (bl);
}
+/* Return the symbol for the function which contains a specified
+ block, described by a struct block BL. The return value will be
+ the closest enclosing function, which might be an inline
+ function. */
+
+struct symbol *
+block_containing_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
/* Return one if BL represents an inlined function. */
int
diff --git a/gdb/block.h b/gdb/block.h
index 1742f24..63b18a6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -131,6 +131,8 @@ struct blockvector
extern struct symbol *block_linkage_function (const struct block *);
+extern struct symbol *block_containing_function (const struct block *);
+
extern int block_inlined_p (const struct block *block);
extern int contained_in (const struct block *, const struct block *);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 66cdfbd..3b00456 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4550,7 +4550,7 @@ print_breakpoint_location (struct breakpoint *b,
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (b->source_file && loc)
+ else if (loc && loc->source_file)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
@@ -4563,7 +4563,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_field_string (uiout, "file", loc->source_file);
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
@@ -4575,7 +4575,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_field_string (uiout, "fullname", fullname);
}
- ui_out_field_int (uiout, "line", b->line_number);
+ ui_out_field_int (uiout, "line", loc->line_number);
}
else if (loc)
{
@@ -5798,12 +5798,6 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sal.symtab->filename);
- b->line_number = sal.line;
-
breakpoints_changed ();
}
@@ -6997,12 +6991,10 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
- if (orig->source_file == NULL)
- copy->source_file = NULL;
- else
- copy->source_file = xstrdup (orig->source_file);
+ if (orig->loc->source_file != NULL)
+ copy->loc->source_file = xstrdup (orig->loc->source_file);
- copy->line_number = orig->line_number;
+ copy->loc->line_number = orig->loc->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
@@ -7086,6 +7078,11 @@ add_location_to_breakpoint (struct breakpoint *b,
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
+
+ if (sal->symtab != NULL)
+ loc->source_file = xstrdup (sal->symtab->filename);
+ loc->line_number = sal->line;
+
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
return loc;
@@ -7142,7 +7139,7 @@ bp_loc_is_permanent (struct bp_location *loc)
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7256,12 +7253,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
me. */
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->filter = filter;
}
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7284,7 +7282,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- cond_string,
+ filter, cond_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
@@ -7294,138 +7292,6 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
install_breakpoint (internal, b);
}
-/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
- elements to fill the void space. */
-static void
-remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
-{
- int i = index_to_remove+1;
- int last_index = sal->nelts-1;
-
- for (;i <= last_index; ++i)
- sal->sals[i-1] = sal->sals[i];
-
- --(sal->nelts);
-}
-
-/* If appropriate, obtains all sals that correspond to the same file
- and line as SAL, in all program spaces. Users debugging with IDEs,
- will want to set a breakpoint at foo.c:line, and not really care
- about program spaces. This is done only if SAL does not have
- explicit PC and has line and file information. If we got just a
- single expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out all sals for
- which the name of enclosing function is different from SAL. This
- makes sure that if we have breakpoint originally set in template
- instantiation, say foo<int>(), we won't expand SAL to locations at
- the same line in all existing instantiations of 'foo'. */
-
-static struct symtabs_and_lines
-expand_line_sal_maybe (struct symtab_and_line sal)
-{
- struct symtabs_and_lines expanded;
- CORE_ADDR original_pc = sal.pc;
- char *original_function = NULL;
- int found;
- int i;
- struct cleanup *old_chain;
-
- /* If we have explicit pc, don't expand.
- If we have no line number, we can't expand. */
- if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
- {
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sal;
- return expanded;
- }
-
- sal.pc = 0;
-
- old_chain = save_current_space_and_thread ();
-
- switch_to_program_space_and_thread (sal.pspace);
-
- find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
- /* Note that expand_line_sal visits *all* program spaces. */
- expanded = expand_line_sal (sal);
-
- if (expanded.nelts == 1)
- {
- /* We had one sal, we got one sal. Return that sal, adjusting it
- past the function prologue if necessary. */
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- skip_prologue_sal (&expanded.sals[0]);
- do_cleanups (old_chain);
- return expanded;
- }
-
- if (!sal.explicit_line)
- {
- CORE_ADDR func_addr, func_end;
- for (i = 0; i < expanded.nelts; ++i)
- {
- CORE_ADDR pc = expanded.sals[i].pc;
- char *this_function;
-
- /* We need to switch threads as well since we're about to
- read memory. */
- switch_to_program_space_and_thread (expanded.sals[i].pspace);
-
- if (find_pc_partial_function (pc, &this_function,
- &func_addr, &func_end))
- {
- if (this_function
- && strcmp (this_function, original_function) != 0)
- {
- remove_sal (&expanded, i);
- --i;
- }
- }
- }
- }
-
- /* Skip the function prologue if necessary. */
- for (i = 0; i < expanded.nelts; ++i)
- skip_prologue_sal (&expanded.sals[i]);
-
- do_cleanups (old_chain);
-
- if (expanded.nelts <= 1)
- {
- /* This is an ugly workaround. If we get zero expanded sals
- then something is really wrong. Fix that by returning the
- original sal. */
-
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- return expanded;
- }
-
- if (original_pc)
- {
- found = 0;
- for (i = 0; i < expanded.nelts; ++i)
- if (expanded.sals[i].pc == original_pc)
- {
- found = 1;
- break;
- }
- gdb_assert (found);
- }
-
- return expanded;
-}
-
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
@@ -7443,7 +7309,6 @@ expand_line_sal_maybe (struct symtab_and_line sal)
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals,
struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
@@ -7452,17 +7317,30 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
int enabled, int internal)
{
int i;
+ struct linespec_sals *lsal;
- for (i = 0; i < sals.nelts; ++i)
+ if (canonical->pre_expanded)
+ gdb_assert (VEC_length (linespec_sals, canonical->sals) == 1);
+
+ for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
{
- struct symtabs_and_lines expanded =
- expand_line_sal_maybe (sals.sals[i]);
+ /* Note that 'addr_string' can be NULL in the case of a plain
+ 'break', without arguments. */
+ char *addr_string = (canonical->addr_string
+ ? xstrdup (canonical->addr_string)
+ : NULL);
+ char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
+ struct cleanup *inner = make_cleanup (xfree, addr_string);
- create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
+ make_cleanup (xfree, filter_string);
+ create_breakpoint_sal (gdbarch, lsal->sals,
+ addr_string,
+ filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
canonical->special_display);
+ discard_cleanups (inner);
}
}
@@ -7476,7 +7354,6 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (char **address,
- struct symtabs_and_lines *sals,
struct linespec_result *canonical)
{
char *addr_start = *address;
@@ -7490,10 +7367,11 @@ parse_breakpoint_sals (char **address,
address. */
if (last_displayed_sal_is_valid ())
{
+ struct linespec_sals lsal;
struct symtab_and_line sal;
init_sal (&sal); /* Initialize to zeroes. */
- sals->sals = (struct symtab_and_line *)
+ lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
/* Set sal's pspace, pc, symtab, and line to the values
@@ -7508,8 +7386,11 @@ parse_breakpoint_sals (char **address,
instances with the same symtab and line. */
sal.explicit_pc = 1;
- sals->sals[0] = sal;
- sals->nelts = 1;
+ lsal.sals.sals[0] = sal;
+ lsal.sals.nelts = 1;
+ lsal.canonical = NULL;
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
else
error (_("No default breakpoint address now."));
@@ -7519,40 +7400,15 @@ parse_breakpoint_sals (char **address,
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving the last displayed codepoint pointers
- alone.
-
- ObjC: However, don't match an Objective-C method name which
- may have a '+' or '-' succeeded by a '[' */
-
- struct symtab_and_line cursal = get_current_source_symtab_and_line ();
-
- if (last_displayed_sal_is_valid ()
- && (!cursal.symtab
- || ((strchr ("+-", (*address)[0]) != NULL)
- && ((*address)[1] != '['))))
- *sals = decode_line_1 (address, 1,
- get_last_displayed_symtab (),
- get_last_displayed_line (),
- canonical);
+ time while leaving default_breakpoint_* alone. */
+ if (last_displayed_sal_is_valid ())
+ decode_line_full (address, 1,
+ get_last_displayed_symtab (),
+ get_last_displayed_line (),
+ canonical, NULL, NULL);
else
- *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- canonical);
- }
- /* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && canonical->canonical == NULL)
- canonical->canonical = xcalloc (sals->nelts, sizeof (char *));
- if (addr_start != (*address))
- {
- int i;
-
- for (i = 0; i < sals->nelts; i++)
- {
- /* Add the string if not present. */
- if (canonical->canonical[i] == NULL)
- canonical->canonical[i] = savestring (addr_start,
- (*address) - addr_start);
- }
+ decode_line_full (address, 1, (struct symtab *) NULL, 0,
+ canonical, NULL, NULL);
}
}
@@ -7587,15 +7443,20 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
for (i = 0; i < sals->nelts; i++)
{
+ struct gdbarch *sarch;
+
sal = &sals->sals[i];
- rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ sarch = get_sal_arch (*sal);
+ if (sarch == NULL)
+ sarch = gdbarch;
+ rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
NULL, &msg);
old_chain = make_cleanup (xfree, msg);
if (!rslt)
error (_("May not have a fast tracepoint at 0x%s%s"),
- paddress (gdbarch, sal->pc), (msg ? msg : ""));
+ paddress (sarch, sal->pc), (msg ? msg : ""));
do_cleanups (old_chain);
}
@@ -7737,8 +7598,6 @@ create_breakpoint (struct gdbarch *gdbarch,
int from_tty, int enabled, int internal)
{
volatile struct gdb_exception e;
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
char *copy_arg;
char *addr_start = arg;
struct linespec_result canonical;
@@ -7751,26 +7610,26 @@ create_breakpoint (struct gdbarch *gdbarch,
gdb_assert (ops != NULL);
- sals.sals = NULL;
- sals.nelts = 0;
init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
int i;
+ struct linespec_sals lsal;
- sals = decode_static_tracepoint_spec (&arg);
+ lsal.sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
- for (i = 0; i < sals.nelts; i++)
- canonical.canonical[i] = xstrdup (copy_arg);
+
+ lsal.canonical = xstrdup (copy_arg);
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+
goto done;
}
TRY_CATCH (e, RETURN_MASK_ALL)
{
- parse_breakpoint_sals (&arg, &sals, &canonical);
+ parse_breakpoint_sals (&arg, &canonical);
}
/* If caller is interested in rc value from parse, set value. */
@@ -7802,35 +7661,31 @@ create_breakpoint (struct gdbarch *gdbarch,
a pending breakpoint and selected yes, or pending
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
- copy_arg = xstrdup (addr_start);
- canonical.canonical = ©_arg;
- sals.nelts = 1;
- sals.sals = &pending_sal;
- pending_sal.pc = 0;
- pending = 1;
+ {
+ struct linespec_sals lsal;
+
+ copy_arg = xstrdup (addr_start);
+ lsal.canonical = xstrdup (copy_arg);
+ lsal.sals.nelts = 1;
+ lsal.sals.sals = XNEW (struct symtab_and_line);
+ init_sal (&lsal.sals.sals[0]);
+ pending = 1;
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+ }
break;
default:
throw_exception (e);
}
break;
default:
- if (!sals.nelts)
+ if (VEC_empty (linespec_sals, canonical.sals))
return 0;
}
done:
/* Create a chain of things that always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- if (!pending)
- {
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the canonical array but not its contents. */
- make_cleanup (xfree, canonical.canonical);
- }
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
@@ -7838,28 +7693,36 @@ create_breakpoint (struct gdbarch *gdbarch,
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the canonical for cleanup. These go on
- the bkpt_chain and only occur if the breakpoint create fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (canonical.canonical[i] != NULL)
- make_cleanup (xfree, canonical.canonical[i]);
- }
-
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ breakpoint_sals_to_pc (&iter->sals);
+ }
/* Fast tracepoints may have additional restrictions on location. */
if (type_wanted == bp_fast_tracepoint)
- check_fast_tracepoint_sals (gdbarch, &sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ check_fast_tracepoint_sals (gdbarch, &iter->sals);
+ }
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
if (!pending)
{
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+
if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
@@ -7868,7 +7731,7 @@ create_breakpoint (struct gdbarch *gdbarch,
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
&thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
@@ -7890,24 +7753,26 @@ create_breakpoint (struct gdbarch *gdbarch,
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (canonical.canonical[0]))
+ && is_marker_spec (lsal->canonical))
{
int i;
- for (i = 0; i < sals.nelts; ++i)
+ for (i = 0; i < lsal->sals.nelts; ++i)
{
struct symtabs_and_lines expanded;
struct tracepoint *tp;
struct cleanup *old_chain;
+ char *addr_string;
expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sals.sals[i];
- old_chain = make_cleanup (xfree, expanded.sals);
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical.addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
- canonical.canonical[i],
+ addr_string, NULL,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
@@ -7923,11 +7788,11 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, &tp->base);
- do_cleanups (old_chain);
+ discard_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
+ create_breakpoints_sal (gdbarch, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
@@ -7942,7 +7807,7 @@ create_breakpoint (struct gdbarch *gdbarch,
b = set_raw_breakpoint_without_location (gdbarch, type_wanted, ops);
set_breakpoint_number (internal, b);
b->thread = -1;
- b->addr_string = canonical.canonical[0];
+ b->addr_string = copy_arg;
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
@@ -7959,7 +7824,7 @@ create_breakpoint (struct gdbarch *gdbarch,
observer_notify_breakpoint_created (b);
}
- if (sals.nelts > 1)
+ if (VEC_length (linespec_sals, canonical.sals) > 1)
{
warning (_("Multiple breakpoints were set.\nUse the "
"\"delete\" command to delete unwanted breakpoints."));
@@ -8340,8 +8205,8 @@ break_range_command (char *arg, int from_tty)
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
- struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
+ struct linespec_sals *lsal_start, *lsal_end;
/* We don't support software ranged breakpoints. */
if (target_ranged_break_num_registers () < 0)
@@ -8354,71 +8219,58 @@ break_range_command (char *arg, int from_tty)
if (can_use_bp < 0)
error (_("Hardware breakpoints used exceeds limit."));
+ arg = skip_spaces (arg);
if (arg == NULL || arg[0] == '\0')
error(_("No address range specified."));
- sals_start.sals = NULL;
- sals_start.nelts = 0;
init_linespec_result (&canonical_start);
- while (*arg == ' ' || *arg == '\t')
- arg++;
-
- parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
+ parse_breakpoint_sals (&arg, &canonical_start);
- sal_start = sals_start.sals[0];
- addr_string_start = canonical_start.canonical[0];
- cleanup_bkpt = make_cleanup (xfree, addr_string_start);
- xfree (sals_start.sals);
- xfree (canonical_start.canonical);
+ cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
if (arg[0] != ',')
error (_("Too few arguments."));
- else if (sals_start.nelts == 0)
+ else if (VEC_empty (linespec_sals, canonical_start.sals))
error (_("Could not find location of the beginning of the range."));
- else if (sals_start.nelts != 1)
+
+ lsal_start = VEC_index (linespec_sals, canonical_start.sals, 0);
+
+ if (VEC_length (linespec_sals, canonical_start.sals) > 1
+ || lsal_start->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_start);
+ sal_start = lsal_start->sals.sals[0];
+ addr_string_start = lsal_start->canonical;
arg++; /* Skip the comma. */
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ arg = skip_spaces (arg);
/* Parse the end location. */
- sals_end.sals = NULL;
- sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
- /* We call decode_line_1 directly here instead of using
+ /* We call decode_line_full directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
- sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
- &canonical_end);
-
- /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
- if (canonical_end.canonical == NULL)
- canonical_end.canonical = xcalloc (1, sizeof (char *));
- /* Add the string if not present. */
- if (arg_start != arg && canonical_end.canonical[0] == NULL)
- canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
-
- sal_end = sals_end.sals[0];
- addr_string_end = canonical_end.canonical[0];
- make_cleanup (xfree, addr_string_end);
- xfree (sals_end.sals);
- xfree (canonical_end.canonical);
-
- if (sals_end.nelts == 0)
+ decode_line_full (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end, NULL, NULL);
+
+ make_cleanup_destroy_linespec_result (&canonical_end);
+
+ if (VEC_empty (linespec_sals, canonical_end.sals))
error (_("Could not find location of the end of the range."));
- else if (sals_end.nelts != 1)
+
+ lsal_end = VEC_index (linespec_sals, canonical_end.sals, 0);
+ if (VEC_length (linespec_sals, canonical_end.sals) > 1
+ || lsal_end->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_end);
+ sal_end = lsal_end->sals.sals[0];
+ addr_string_end = lsal_end->canonical;
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
@@ -8445,11 +8297,11 @@ break_range_command (char *arg, int from_tty)
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
- b->addr_string = addr_string_start;
- b->addr_string_range_end = addr_string_end;
+ b->addr_string = xstrdup (addr_string_start);
+ b->addr_string_range_end = xstrdup (addr_string_end);
b->loc->length = length;
- discard_cleanups (cleanup_bkpt);
+ do_cleanups (cleanup_bkpt);
mention (b);
observer_notify_breakpoint_created (b);
@@ -9558,10 +9410,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&arg, 1,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
@@ -10144,18 +9995,21 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
- && (loc->pspace == sal.pspace)
- && (loc->address == sal.pc)
- && (!section_is_overlay (loc->section)
- || loc->section == sal.section);
- int line_match = ((default_match || (0 == sal.pc))
- && b->source_file != NULL
+ /* If the user specified file:line, don't allow a PC
+ match. This matches historical gdb behavior. */
+ int pc_match = (!sal.explicit_line
+ && sal.pc
+ && (loc->pspace == sal.pspace)
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section));
+ int line_match = ((default_match || sal.explicit_line)
+ && loc->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && filename_cmp (b->source_file,
+ && filename_cmp (loc->source_file,
sal.symtab->filename) == 0
- && b->line_number == sal.line);
+ && loc->line_number == sal.line);
if (pc_match || line_match)
{
match = 1;
@@ -10747,15 +10601,25 @@ say_where (struct breakpoint *b)
}
else
{
- if (opts.addressprint || b->source_file == NULL)
+ if (opts.addressprint || b->loc->source_file == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
if (b->loc->next)
{
@@ -10775,6 +10639,7 @@ bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
xfree (self->function_name);
+ xfree (self->source_file);
}
static const struct bp_location_ops bp_location_ops =
@@ -10791,8 +10656,8 @@ base_breakpoint_dtor (struct breakpoint *self)
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
xfree (self->addr_string);
+ xfree (self->filter);
xfree (self->addr_string_range_end);
- xfree (self->source_file);
}
static struct bp_location *
@@ -11623,17 +11488,18 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
ui_out_field_int (uiout, "line", sal.line);
ui_out_text (uiout, "\n");
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
- xfree (b->source_file);
+ xfree (b->loc->source_file);
if (sym)
- b->source_file = xstrdup (sal.symtab->filename);
+ b->loc->source_file = xstrdup (sal.symtab->filename);
else
- b->source_file = NULL;
+ b->loc->source_file = NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal.symtab->filename, b->line_number);
+ sal.symtab->filename,
+ b->loc->line_number);
/* Might be nice to check if function changed, and warn if
so. */
@@ -11683,8 +11549,17 @@ update_breakpoint_locations (struct breakpoint *b,
int i;
struct bp_location *existing_locations = b->loc;
- /* Ranged breakpoints have only one start location and one end location. */
- gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+ if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
+ {
+ /* Ranged breakpoints have only one start location and one end
+ location. */
+ b->enable_state = bp_disabled;
+ update_global_location_list (1);
+ printf_unfiltered (_("Could not reset ranged breakpoint %d: "
+ "multiple locations found\n"),
+ b->number);
+ return;
+ }
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
@@ -11699,8 +11574,11 @@ update_breakpoint_locations (struct breakpoint *b,
for (i = 0; i < sals.nelts; ++i)
{
- struct bp_location *new_loc =
- add_location_to_breakpoint (b, &(sals.sals[i]));
+ struct bp_location *new_loc;
+
+ switch_to_program_space_and_thread (sals.sals[i].pspace);
+
+ new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
/* Reparse conditions, they might contain references to the
old symtab. */
@@ -11724,16 +11602,6 @@ update_breakpoint_locations (struct breakpoint *b,
}
}
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sals.sals[i].symtab->filename);
-
- if (b->line_number == 0)
- b->line_number = sals.sals[i].line;
-
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
@@ -11800,7 +11668,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
char *s;
int marker_spec;
struct symtabs_and_lines sals = {0};
- struct gdb_exception e;
+ volatile struct gdb_exception e;
s = addr_string;
marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
@@ -11821,7 +11689,30 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
error (_("marker %s not found"), tp->static_trace_marker_id);
}
else
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ {
+ struct linespec_result canonical;
+
+ init_linespec_result (&canonical);
+ decode_line_full (&s, 1, (struct symtab *) NULL, 0,
+ &canonical, multiple_symbols_all,
+ b->filter);
+
+ /* We should get 0 or 1 resulting SALs. */
+ gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
+
+ if (VEC_length (linespec_sals, canonical.sals) > 0)
+ {
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ sals = lsal->sals;
+ /* Arrange it so the destructor does not free the
+ contents. */
+ lsal->sals.sals = NULL;
+ }
+
+ destroy_linespec_result (&canonical);
+ }
}
if (e.reason < 0)
{
@@ -11855,9 +11746,10 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
{
- gdb_assert (sals.nelts == 1);
+ int i;
- resolve_sal_pc (&sals.sals[0]);
+ for (i = 0; i < sals.nelts; ++i)
+ resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
char *cond_string = 0;
@@ -11900,7 +11792,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals.sals);
- expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = sals;
}
if (b->addr_string_range_end)
@@ -11909,7 +11801,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals_end.sals);
- expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ expanded_end = sals_end;
}
}
@@ -12447,11 +12339,10 @@ decode_line_spec_1 (char *string, int funfirstline)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&string, funfirstline,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, NULL);
+ (struct symtab *) NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 9defd02..2bd5ea8 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -397,6 +397,14 @@ struct bp_location
This variable keeps a number of events still to go, when
it becomes 0 this location is retired. */
int events_till_retirement;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ char *source_file;
};
/* This structure is a collection of function pointers that, if available,
@@ -544,14 +552,6 @@ struct breakpoint
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
- /* Line number of this address. */
-
- int line_number;
-
- /* Source file name of this address. */
-
- char *source_file;
-
/* Non-zero means a silent breakpoint (don't print frame info
if we stop here). */
unsigned char silent;
@@ -575,6 +575,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
+ /* The filter that should be passed to decode_line_full when
+ re-setting this breakpoint. This may be NULL, but otherwise is
+ allocated with xmalloc. */
+ char *filter;
+
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index d75a6c0..25e60e1 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -92,6 +92,9 @@ void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
@@ -246,16 +249,6 @@ help_command (char *command, int from_tty)
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
@@ -796,8 +789,9 @@ edit_command (char *arg, int from_tty)
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
@@ -926,8 +920,9 @@ list_command (char *arg, int from_tty)
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
@@ -959,9 +954,10 @@ list_command (char *arg, int from_tty)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals_end = decode_line_list (&arg1, 0, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ sals_end = decode_line_list (&arg1, 0, sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
@@ -1472,6 +1468,85 @@ ambiguous_line_spec (struct symtabs_and_lines *sals)
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ || sals->sals[i].symtab == NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
diff --git a/gdb/defs.h b/gdb/defs.h
index b5bc6c5..040d9c9 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -425,6 +425,7 @@ char *ldirname (const char *filename);
char **gdb_buildargv (const char *);
int compare_positive_ints (const void *ap, const void *bp);
+int compare_strings (const void *ap, const void *bp);
/* A wrapper for bfd_errmsg to produce a more helpful error message
in the case of bfd_error_file_ambiguously recognized.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8a7d7e9..7547a40 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -443,9 +443,6 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
return sym;
}
-/* Define VEC (CORE_ADDR) functions. */
-DEF_VEC_I (CORE_ADDR);
-
/* Verify function with entry point exact address ADDR can never call itself
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
can call itself via tail calls.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 5e279de..de1aac3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2439,10 +2439,38 @@ dw2_forget_cached_source_info (struct objfile *objfile)
dw2_free_cached_file_names, NULL);
}
+/* Helper function for dw2_map_symtabs_matching_filename that expands
+ the symtabs and calls the iterator. */
+
+static int
+dw2_map_expand_apply (struct objfile *objfile,
+ struct dwarf2_per_cu_data *per_cu,
+ const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded CUs. */
+ if (per_cu->v.quick->symtab)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ dw2_instantiate_symtab (objfile, per_cu);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
static int
-dw2_lookup_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
+dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
{
int i;
const char *name_basename = lbasename (name);
@@ -2471,8 +2499,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (FILENAME_CMP (name, this_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
if (check_basename && ! base_cu
@@ -2493,8 +2523,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (full_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
@@ -2506,8 +2538,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
}
@@ -2515,8 +2549,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (base_cu)
{
- *result = dw2_instantiate_symtab (objfile, base_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, base_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
return 0;
@@ -2862,7 +2898,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
- dw2_lookup_symtab,
+ dw2_map_symtabs_matching_filename,
dw2_lookup_symbol,
dw2_pre_expand_symtabs_matching,
dw2_print_stats,
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 64ba837..87f24d9 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -45,108 +45,246 @@
#include "cli/cli-utils.h"
#include "filenames.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_variable (struct linespec_state *self,
+ char *copy);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symtab *symtab_from_filename (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 symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+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_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+/* Helper functions. */
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Add SAL to SALS. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+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 decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* 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 symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+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);
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+ if (self->canonical)
+ {
+ char *canonical_name = NULL;
-/* Helper functions. */
+ self->canonical_names = xrealloc (self->canonical_names,
+ sals->nelts * sizeof (char *));
+ if (sal->symtab && sal->symtab->filename)
+ {
+ char *filename = sal->symtab->filename;
+
+ /* FIXME: this is where we should do "FILE:FUNCTION:LINE",
+ to let us distinguish between different template
+ instantiations. */
+ 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 +319,64 @@ 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 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 (strcmp_iw (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;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
+ if (pspace->executing_startup)
+ continue;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ set_current_program_space (pspace);
- return count;
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+ iterate_name_matcher,
+ ALL_DOMAIN,
+ &name);
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ iterate_over_symbols (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -227,40 +403,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 +448,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;
-}
-
-/* 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;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-
-
/* 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 +529,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 +684,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 +827,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 +847,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 +893,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 +926,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 +959,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 +981,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 +1005,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 +1031,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,91 +1079,238 @@ 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;
+ }
}
-\f
+/* A constructor for linespec_state. */
-/* 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. */
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int funfirstline,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = funfirstline;
+ 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);
+}
-/* First, some functions to initialize stuff at the beggining of the
- function. */
+/* A destructor for linespec_state. */
static void
-initialize_defaults (struct symtab **default_symtab, int *default_line)
+linespec_state_destructor (void *arg)
{
- if (*default_symtab == 0)
- {
- /* Use whatever we have for the default source line. We don't use
- get_current_or_default_symtab_and_line as it can recurse and call
- us back! */
- struct symtab_and_line cursal =
- get_current_source_symtab_and_line ();
-
- *default_symtab = cursal.symtab;
- *default_line = cursal.line;
- }
-}
+ struct linespec_state *self = arg;
-\f
+ xfree (self->user_filename);
+ xfree (self->user_function);
+ VEC_free (symtab_p, self->file_symtabs);
+ htab_delete (self->addr_set);
+}
-/* Decode arg of the form *PC. */
+/* See linespec.h. */
-static struct symtabs_and_lines
-decode_indirect (char **argptr)
+void
+decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter)
{
- struct symtabs_and_lines values;
- CORE_ADDR pc;
+ 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);
+
+ linespec_state_constructor (&state, funfirstline, 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;
+
+ 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 funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, 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;
+}
+
+/* See linespec.h. */
+
+struct symtabs_and_lines
+decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, default_symtab,
+ default_line, NULL);
+ state.list_mode = 1;
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+\f
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+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 +1323,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 +1433,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 +1461,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,
- ¤t_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,9 +1515,8 @@ 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;
@@ -1381,10 +1524,9 @@ decode_compound (char **argptr, int funfirstline,
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 +1561,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 +1661,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 +1718,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,8 +1728,10 @@ 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. */
@@ -1611,7 +1751,6 @@ decode_compound (char **argptr, int funfirstline,
/* Look up entire name. */
name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
@@ -1619,213 +1758,400 @@ decode_compound (char **argptr, int funfirstline,
make_cleanup (xfree, name);
}
- 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;
+ return decode_variable (self, copy);
+}
- /* 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);
- }
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* 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);
-}
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
+
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
+
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
-/* Next come some helper functions for decode_compound. */
+ 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);
+ }
+
+ 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);
+ iterate_over_symbols (search_block, copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ 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;
+}
- i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
- file_symtab);
+/* 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;
- /* 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)
+ for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix)
+ add_matching_symbols_to_info (iter, info, pspace);
+}
+
+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);
+
+ 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);
+}
+
+\f
+
+/* 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;
}
-\f
+/* 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;
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+ 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);
+ }
+
+ do_cleanups (cleanups);
+ return collector.symtabs;
+}
-static struct symtab *
-symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+/* Return all the symtabs associated to the filename given by the
+ substring of *ARGPTR ending at P, and advance ARGPTR past that
+ filename. */
+
+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 +2160,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 +2173,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,18 +2222,40 @@ 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 looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (VEC_empty (symbolp, result)
+ && current_language->la_language == language_ada)
+ {
+ struct symbol *function_symbol;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ xfree (copy);
+ copy = xstrdup (SYMBOL_SEARCH_NAME (function_symbol));
+ *user_function = copy;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols,
+ &result, NULL);
+ }
+ }
+
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ return result;
}
\f
@@ -1901,13 +2265,16 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
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 ix;
+ struct symtab *elt;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1915,12 +2282,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 +2292,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 +2317,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 +2332,77 @@ 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);
+
+ 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));
+
+ if (self->list_mode)
+ {
+ /* 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);
+ }
+ else
+ {
+ int pcix;
+ CORE_ADDR pc;
+ VEC (CORE_ADDR) *pcs;
+
+ pcs = find_pcs_for_symtab_line (elt, val.line);
+ if (VEC_empty (CORE_ADDR, pcs))
+ continue;
+
+ for (pcix = 0; VEC_iterate (CORE_ADDR, pcs, pcix, pc); ++pcix)
+ {
+ val.symtab = elt;
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = pc;
+ val.explicit_line = 1;
+
+ skip_prologue_sal (&val);
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
+
+ VEC_free (CORE_ADDR, pcs);
+ }
+ }
+
+ 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 +2411,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 +2443,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 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.reason == 0)
+ return values;
+
+ 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 +2464,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;
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ 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 +2503,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 +2512,308 @@ 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)
{
+ 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_selected_block (0);
+
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;
+ }
+
+ 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)
+ {
+ 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;
+
+ 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, ¤t_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);
+}
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+/* Search minimal symbols in all objfiles for NAME. If SEARCH_PSPACE
+ is not NULL, the search is restricted to just that program
+ space. */
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+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;
- return sym != NULL;
+ 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));
+ 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);
+ 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);
+
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
- name = canon;
- make_cleanup (xfree, name);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (sym != NULL)
+ /* If looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (info.result.nelts == 0 && current_language->la_language == language_ada)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
- }
+ struct symbol *sym;
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ sym = lookup_symbol (lookup_name, get_selected_block (0), VAR_DOMAIN, 0);
+ if (sym)
+ {
+ copy = SYMBOL_SEARCH_NAME (sym);
+ add_matching_symbols_to_info (copy, &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 +2822,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,
- ¤t_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;
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+ 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);
+}
- values.nelts = 1;
- return values;
+/* Cleanup function for a linespec_result. */
+
+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);
}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 3c86af3..d32f401 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -20,8 +20,30 @@
struct symtab;
+#include "vec.h"
+
+/* decode_line_full returns a vector of these. */
+
+struct linespec_sals
+{
+ /* This is the linespec corresponding to the sals contained in this
+ object. It can be passed as the FILTER argument to future calls
+ to decode_line_full. This is freed by
+ destroy_linespec_result. */
+ char *canonical;
+
+ /* Sals. The 'sals' field is destroyed by
+ destroy_linespec_result. */
+ struct symtabs_and_lines sals;
+};
+
+typedef struct linespec_sals linespec_sals;
+DEF_VEC_O (linespec_sals);
+
/* An instance of this may be filled in by decode_line_1. The caller
- must call init_linespec_result to initialize it. */
+ must call init_linespec_result to initialize it and
+ destroy_linespec_result to destroy it. The caller must make copies
+ of any data that it needs to keep. */
struct linespec_result
{
@@ -30,22 +52,85 @@ struct linespec_result
display mechanism would do the wrong thing. */
int special_display;
- /* If non-NULL, an array of canonical names for returned
- symtab_and_line objects. The array has as many elements as the
- `nelts' field in the symtabs_and_line returned by decode_line_1.
- An element in the array may be NULL. The array and each non-NULL
- element in it are allocated with xmalloc and must be freed by the
- caller. */
- char **canonical;
+ /* If non-zero, the linespec result should be considered to be a
+ "pre-expanded" multi-location linespec. A pre-expanded linespec
+ holds all matching locations in a single linespec_sals
+ object. */
+ int pre_expanded;
+
+ /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+ by the user. This will be freed by destroy_linespec_result. */
+ char *addr_string;
+
+ /* The sals. The vector will be freed by
+ destroy_linespec_result. */
+ VEC (linespec_sals) *sals;
};
/* Initialize a linespec_result. */
extern void init_linespec_result (struct linespec_result *);
+/* Destroy a linespec_result. */
+
+extern void destroy_linespec_result (struct linespec_result *);
+
+/* Return a cleanup that destroys a linespec_result. */
+
+extern struct cleanup *
+ make_cleanup_destroy_linespec_result (struct linespec_result *);
+
extern struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline,
- struct symtab *default_symtab, int default_line,
- struct linespec_result *canonical);
+ struct symtab *default_symtab, int default_line);
+
+/* Like decode_line_1, but useful only for the 'list' command. With
+ this variant, a "file:line" linespec will always return a result. */
+
+extern struct symtabs_and_lines
+ decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line);
+
+/* Parse *ARGPTR as a linespec and return results. This is the "full"
+ interface to this module, which handles multiple results
+ properly.
+
+ FUNFIRSTLINE is nonzero if we want the resulting SALs to describe
+ the first line of indicated functions.
+
+ DEFAULT_SYMTAB and DEFAULT_LINE describe the default location.
+ DEFAULT_SYMTAB can be NULL, in which case the current symtab and
+ line are used.
+
+ CANONICAL is where the results are stored. It must not be NULL.
+
+ SELECT_MODE must be one of the multiple_symbols_* constants, or
+ NULL. It determines how multiple results will be handled. If
+ NULL, the appropriate CLI value will be used.
+
+ FILTER can either be NULL or a string holding a canonical name.
+ This is only valid when SELECT_MODE is multiple_symbols_all.
+
+ Multiple results are handled differently depending on the
+ arguments:
+
+ . With multiple_symbols_cancel, an exception is thrown.
+
+ . With multiple_symbols_ask, a menu is presented to the user. The
+ user may select none, in which case an exception is thrown; or all,
+ which is handled like multiple_symbols_all, below. Otherwise,
+ CANONICAL->SALS will have one entry for each name the user chose.
+
+ . With multiple_symbols_all, CANONICAL->SALS will have a single
+ entry describing all the matching locations. If FILTER is
+ non-NULL, then only locations whose canonical name is equal (in the
+ strcmp sense) to FILTER will be returned; all others will be
+ filtered out. */
+
+extern void decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter);
#endif /* defined (LINESPEC_H) */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 70871cd..f90f036 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -310,6 +310,46 @@ lookup_minimal_symbol (const char *name, const char *sfile,
return NULL;
}
+/* Iterate over all the minimal symbols in the objfile OBJF which
+ match NAME. Both the ordinary and demangled names of each symbol
+ are considered. The caller is responsible for canonicalizing NAME,
+ should that need to be done.
+
+ For each matching symbol, CALLBACK is called with the symbol and
+ USER_DATA as arguments. */
+
+void
+iterate_over_minimal_symbols (struct objfile *objf, const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data)
+{
+ unsigned int hash;
+ struct minimal_symbol *iter;
+ int (*cmp) (const char *, const char *);
+
+ /* The first pass is over the ordinary hash table. */
+ hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_hash[hash];
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+ while (iter)
+ {
+ if (cmp (SYMBOL_LINKAGE_NAME (iter), name) == 0)
+ (*callback) (iter, user_data);
+ iter = iter->hash_next;
+ }
+
+ /* The second pass is over the demangled table. */
+ hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_demangled_hash[hash];
+ while (iter)
+ {
+ if (SYMBOL_MATCHES_SEARCH_NAME (iter, name))
+ (*callback) (iter, user_data);
+ iter = iter->demangled_hash_next;
+ }
+}
+
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a pointer
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 592b52e..dcf9459 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -952,49 +952,7 @@ classes_info (char *regexp, int from_tty)
printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
-/*
- * Function: find_imps (char *selector, struct symbol **sym_arr)
- *
- * Input: a string representing a selector
- * a pointer to an array of symbol pointers
- * possibly a pointer to a symbol found by the caller.
- *
- * Output: number of methods that implement that selector. Side
- * effects: The array of symbol pointers is filled with matching syms.
- *
- * By analogy with function "find_methods" (symtab.c), builds a list
- * of symbols matching the ambiguous input, so that "decode_line_2"
- * (symtab.c) can list them and ask the user to choose one or more.
- * In this case the matches are objective c methods
- * ("implementations") matching an objective c selector.
- *
- * Note that it is possible for a normal (c-style) function to have
- * the same name as an objective c selector. To prevent the selector
- * from eclipsing the function, we allow the caller (decode_line_1) to
- * search for such a function first, and if it finds one, pass it in
- * to us. We will then integrate it into the list. We also search
- * for one here, among the minsyms.
- *
- * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
- * into two parts: debuggable (struct symbol) syms, and
- * non_debuggable (struct minimal_symbol) syms. The debuggable
- * ones will come first, before NUM_DEBUGGABLE (which will thus
- * be the index of the first non-debuggable one).
- */
-
-/*
- * Function: total_number_of_imps (char *selector);
- *
- * Input: a string representing a selector
- * Output: number of methods that implement that selector.
- *
- * By analogy with function "total_number_of_methods", this allows
- * decode_line_1 (symtab.c) to detect if there are objective c methods
- * matching the input, and to allocate an array of pointers to them
- * which can be manipulated by "decode_line_2" (also in symtab.c).
- */
-
-char *
+static char *
parse_selector (char *method, char **selector)
{
char *s1 = NULL;
@@ -1050,7 +1008,7 @@ parse_selector (char *method, char **selector)
return s2;
}
-char *
+static char *
parse_method (char *method, char *type, char **class,
char **category, char **selector)
{
@@ -1154,15 +1112,11 @@ parse_method (char *method, char *type, char **class,
}
static void
-find_methods (struct symtab *symtab, char type,
- const char *class, const char *category,
- const char *selector, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+find_methods (char type, const char *class, const char *category,
+ const char *selector,
+ VEC (const_char_ptr) **symbol_names)
{
struct objfile *objfile = NULL;
- struct minimal_symbol *msymbol = NULL;
- struct block *block = NULL;
- struct symbol *sym = NULL;
char *symname = NULL;
@@ -1171,21 +1125,15 @@ find_methods (struct symtab *symtab, char type,
char *ncategory = NULL;
char *nselector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
static char *tmp = NULL;
static unsigned int tmplen = 0;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
-
- if (symtab)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ gdb_assert (symbol_names != NULL);
ALL_OBJFILES (objfile)
{
unsigned int *objc_csym;
+ struct minimal_symbol *msymbol = NULL;
/* The objfile_csym variable counts the number of ObjC methods
that this objfile defines. We save that count as a private
@@ -1202,7 +1150,6 @@ find_methods (struct symtab *symtab, char type,
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
QUIT;
@@ -1216,18 +1163,8 @@ find_methods (struct symtab *symtab, char type,
/* Not a method name. */
continue;
- /* 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, pc,
- ¤t_target);
-
objfile_csym++;
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
/* Now that thinks are a bit sane, clean up the symname. */
while ((strlen (symname) + 1) >= tmplen)
{
@@ -1255,41 +1192,9 @@ find_methods (struct symtab *symtab, char type,
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
- sym = find_pc_function (pc);
- if (sym != NULL)
- {
- const char *newsymname = SYMBOL_NATURAL_NAME (sym);
-
- if (strcmp (symname, newsymname) == 0)
- {
- /* Found a high-level method sym: swap it into the
- lower part of sym_arr (below num_debuggable). */
- if (syms != NULL)
- {
- syms[csym] = syms[cdebug];
- syms[cdebug] = sym;
- }
- csym++;
- cdebug++;
- }
- else
- {
- warning (
-"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
- newsymname, symname);
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
- }
- else
- {
- /* Found a non-debuggable method symbol. */
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
+ VEC_safe_push (const_char_ptr, *symbol_names, symname);
}
+
if (objc_csym == NULL)
{
objc_csym = obstack_alloc (&objfile->objfile_obstack,
@@ -1301,38 +1206,79 @@ find_methods (struct symtab *symtab, char type,
/* Count of ObjC methods in this objfile should be constant. */
gdb_assert (*objc_csym == objfile_csym);
}
+}
+
+/* Uniquify a VEC of strings. */
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
+static void
+uniquify_strings (VEC (const_char_ptr) **strings)
+{
+ int ix;
+ const char *elem, *last = NULL;
+ int out;
+
+ qsort (VEC_address (const_char_ptr, *strings),
+ VEC_length (const_char_ptr, *strings),
+ sizeof (const_char_ptr),
+ compare_strings);
+ out = 0;
+ for (ix = 0; VEC_iterate (const_char_ptr, *strings, ix, elem); ++ix)
+ {
+ if (last == NULL || strcmp (last, elem) != 0)
+ {
+ /* Keep ELEM. */
+ VEC_replace (const_char_ptr, *strings, out, elem);
+ ++out;
+ }
+ last = elem;
+ }
+ VEC_truncate (const_char_ptr, *strings, out);
}
-char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+char *
+find_imps (char *method, VEC (const_char_ptr) **symbol_names)
{
char type = '\0';
char *class = NULL;
char *category = NULL;
char *selector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
- unsigned int ncsym = 0;
- unsigned int ncdebug = 0;
-
char *buf = NULL;
char *tmp = NULL;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
+ int selector_case = 0;
- if (nsym != NULL)
- *nsym = 0;
- if (ndebug != NULL)
- *ndebug = 0;
+ gdb_assert (symbol_names != NULL);
buf = (char *) alloca (strlen (method) + 1);
strcpy (buf, method);
@@ -1340,99 +1286,37 @@ char *find_imps (struct symtab *symtab, struct block *block,
if (tmp == NULL)
{
- struct symbol *sym = NULL;
- struct minimal_symbol *msym = NULL;
-
strcpy (buf, method);
tmp = parse_selector (buf, &selector);
if (tmp == NULL)
return NULL;
- sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
- if (sym != NULL)
- {
- if (syms)
- syms[csym] = sym;
- csym++;
- cdebug++;
- }
-
- if (sym == NULL)
- msym = lookup_minimal_symbol (selector, 0, 0);
-
- if (msym != NULL)
- {
- if (syms)
- syms[csym] = (struct symbol *)msym;
- csym++;
- }
+ selector_case = 1;
}
- if (syms != NULL)
- find_methods (symtab, type, class, category, selector,
- syms + csym, &ncsym, &ncdebug);
- else
- find_methods (symtab, type, class, category, selector,
- NULL, &ncsym, &ncdebug);
-
- /* If we didn't find any methods, just return. */
- if (ncsym == 0 && ncdebug == 0)
- return method;
+ find_methods (type, class, category, selector, symbol_names);
- /* Take debug symbols from the second batch of symbols and swap them
- * with debug symbols from the first batch. Repeat until either the
- * second section is out of debug symbols or the first section is
- * full of debug symbols. Either way we have all debug symbols
- * packed to the beginning of the buffer.
- */
-
- if (syms != NULL)
+ /* If we hit the "selector" case, and we found some methods, then
+ add the selector itself as a symbol, if it exists. */
+ if (selector_case && !VEC_empty (const_char_ptr, *symbol_names))
{
- while ((cdebug < csym) && (ncdebug > 0))
+ struct symbol *sym = lookup_symbol (selector, NULL, VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (sym));
+ else
{
- struct symbol *s = NULL;
- /* First non-debugging symbol. */
- unsigned int i = cdebug;
- /* Last of second batch of debug symbols. */
- unsigned int j = csym + ncdebug - 1;
-
- s = syms[j];
- syms[j] = syms[i];
- syms[i] = s;
-
- /* We've moved a symbol from the second debug section to the
- first one. */
- cdebug++;
- ncdebug--;
+ struct minimal_symbol *msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (msym));
}
}
- csym += ncsym;
- cdebug += ncdebug;
-
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
-
- if (syms == NULL)
- return method + (tmp - buf);
-
- if (csym > 1)
- {
- /* Sort debuggable symbols. */
- if (cdebug > 1)
- qsort (syms, cdebug, sizeof (struct minimal_symbol *),
- compare_classes);
-
- /* Sort minimal_symbols. */
- if ((csym - cdebug) > 1)
- qsort (&syms[cdebug], csym - cdebug,
- sizeof (struct minimal_symbol *), compare_classes);
- }
- /* Terminate the sym_arr list. */
- syms[csym] = 0;
+ uniquify_strings (symbol_names);
return method + (tmp - buf);
}
diff --git a/gdb/objc-lang.h b/gdb/objc-lang.h
index ee4cc29..351af7b 100644
--- a/gdb/objc-lang.h
+++ b/gdb/objc-lang.h
@@ -21,6 +21,8 @@
#if !defined(OBJC_LANG_H)
#define OBJC_LANG_H
+#include "cp-support.h" /* For VEC (const_char_ptr) */
+
struct stoken;
struct value;
@@ -39,15 +41,7 @@ extern char *objc_demangle (const char *mangled, int options);
extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
-extern char *parse_selector (char *method, char **selector);
-
-extern char *parse_method (char *method, char *type,
- char **class, char **category,
- char **selector);
-
-extern char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug);
+extern char *find_imps (char *method, VEC (const_char_ptr) **symbol_names);
extern struct value *value_nsstring (struct gdbarch *gdbarch,
char *ptr, int len);
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 6c4507d..c20fd78 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -125,13 +125,42 @@ require_partial_symbols (struct objfile *objfile, int verbose)
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p)
-/* Lookup the partial symbol table of a source file named NAME.
- *If* there is no '/' in the name, a match after a '/'
- in the psymtab filename will also work. */
+/* Helper function for partial_map_symtabs_matching_filename that
+ expands the symtabs and calls the iterator. */
-static struct partial_symtab *
-lookup_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path)
+static int
+partial_map_expand_apply (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ struct partial_symtab *pst,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded psymtabs. */
+ if (pst->readin)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ psymtab_to_symtab (pst);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
+static int
+partial_map_symtabs_matching_filename (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data)
{
struct partial_symtab *pst;
const char *name_basename = lbasename (name);
@@ -140,7 +169,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
/* Before we invoke realpath, which can get expensive when many
@@ -157,7 +188,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
if (pst->fullname != NULL
&& FILENAME_CMP (full_path, pst->fullname) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
@@ -172,7 +205,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
}
if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
}
@@ -183,29 +218,12 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path, pst,
+ callback, data))
+ return 1;
}
- return (NULL);
-}
-
-static int
-lookup_symtab_via_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
-{
- struct partial_symtab *ps;
-
- ps = lookup_partial_symtab (objfile, name, full_path, real_path);
- if (!ps)
- return 0;
-
- if (ps->readin)
- error (_("Internal: readin %s pst for `%s' found when no symtab found."),
- ps->filename, name);
-
- *result = PSYMTAB_TO_SYMTAB (ps);
- return 1;
+ return 0;
}
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
@@ -1304,7 +1322,7 @@ const struct quick_symbol_functions psym_functions =
objfile_has_psyms,
find_last_source_symtab_from_partial,
forget_cached_source_info_partial,
- lookup_symtab_via_partial_symtab,
+ partial_map_symtabs_matching_filename,
lookup_symbol_aux_psymtabs,
pre_expand_symtabs_matching_psymtabs,
print_psymtab_stats_for_objfile,
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index f76b1c7..b038e03 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -934,7 +934,7 @@ DEF_VEC_O (type_equality_entry_d);
the same, 0 otherwise. Handles NULLs properly. */
static int
-compare_strings (const char *s, const char *t)
+compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
@@ -970,9 +970,10 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
- if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
+ TYPE_TAG_NAME (type2)))
return Py_NE;
- if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
@@ -995,7 +996,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
- if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_NAME (*field1),
+ FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
@@ -1009,8 +1011,8 @@ check_types_equal (struct type *type1, struct type *type2,
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
- if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
- FIELD_STATIC_PHYSNAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
+ FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 108e542..b898313 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -512,7 +512,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
{
copy = xstrdup (arg);
make_cleanup (xfree, copy);
- sals = decode_line_1 (©, 0, 0, 0, 0);
+ sals = decode_line_1 (©, 0, 0, 0);
make_cleanup (xfree, sals.sals);
}
else
diff --git a/gdb/skip.c b/gdb/skip.c
index 4bda3c4..29c7521 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -164,7 +164,7 @@ skip_function_command (char *arg, int from_tty)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&arg, 1, 0, 0, 0);
+ sals = decode_line_1 (&arg, 1, 0, 0);
}
if (decode_exception.reason < 0)
@@ -514,7 +514,7 @@ skip_re_set (void)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&func_name, 1, 0, 0, 0);
+ sals = decode_line_1 (&func_name, 1, 0, 0);
}
if (decode_exception.reason >= 0
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 888aa34..21efbdf 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -28,8 +28,6 @@
#include "gdb_string.h"
-DEF_VEC_I(CORE_ADDR);
-
/* Private data for each loaded library. */
struct lm_info
{
diff --git a/gdb/source.c b/gdb/source.c
index 77df541..49e9e49 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1413,12 +1413,14 @@ line_info (char *arg, int from_tty)
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
@@ -1432,11 +1434,15 @@ line_info (char *arg, int from_tty)
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
@@ -1502,7 +1508,7 @@ line_info (char *arg, int from_tty)
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */
diff --git a/gdb/stack.c b/gdb/stack.c
index 9136daa..48c1c27 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2444,20 +2444,25 @@ func_command (char *arg, int from_tty)
int i;
int level = 1;
struct function_bounds *func_bounds = NULL;
+ struct cleanup *cleanups;
if (arg != NULL)
return;
frame = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
+ cleanups = make_cleanup (xfree, sals.sals);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
+ make_cleanup (xfree, func_bounds);
for (i = 0; (i < sals.nelts && !found); i++)
{
- if (sals.sals[i].pc == 0
- || find_pc_partial_function (sals.sals[i].pc, NULL,
- &func_bounds[i].low,
- &func_bounds[i].high) == 0)
+ if (sals.sals[i].pspace != current_program_space)
+ func_bounds[i].low = func_bounds[i].high = 0;
+ else if (sals.sals[i].pc == 0
+ || find_pc_partial_function (sals.sals[i].pc, NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
{
func_bounds[i].low = func_bounds[i].high = 0;
}
@@ -2476,8 +2481,7 @@ func_command (char *arg, int from_tty)
}
while (!found && level == 0);
- if (func_bounds)
- xfree (func_bounds);
+ do_cleanups (cleanups);
if (!found)
printf_filtered (_("'%s' not within current stack frame.\n"), arg);
diff --git a/gdb/symfile.h b/gdb/symfile.h
index accd20e..dfe5042 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -152,22 +152,24 @@ struct quick_symbol_functions
/* Forget all cached full file names for OBJFILE. */
void (*forget_cached_source_info) (struct objfile *objfile);
- /* Look up the symbol table, in OBJFILE, of a source file named
- NAME. If there is no '/' in the name, a match after a '/' in the
- symbol table's file name will also work. FULL_PATH is the
- absolute file name, and REAL_PATH is the same, run through
- gdb_realpath.
-
- If no such symbol table can be found, returns 0.
-
- Otherwise, sets *RESULT to the symbol table and returns 1. This
- might return 1 and set *RESULT to NULL if the requested file is
- an include file that does not have a symtab of its own. */
- int (*lookup_symtab) (struct objfile *objfile,
- const char *name,
- const char *full_path,
- const char *real_path,
- struct symtab **result);
+ /* Expand and iterate over each "partial" symbol table in OBJFILE
+ where the source file is named NAME.
+
+ If there is no '/' in the name, a match after a '/' in the symbol
+ table's file name will also work. FULL_PATH is the absolute file
+ name, and REAL_PATH is the same, run through gdb_realpath.
+
+ If a match is found, the "partial" symbol table is expanded.
+ Then, this calls iterate_over_some_symtabs (or equivalent) over
+ all newly-created symbol tables, passing CALLBACK and DATA to it.
+ The result of this call is returned. */
+ int (*map_symtabs_matching_filename) (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data);
/* Check to see if the symbol is defined in a "partial" symbol table
of OBJFILE. KIND should be either GLOBAL_BLOCK or STATIC_BLOCK,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3d94e6b..127fc8e 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -81,7 +81,7 @@ static void sources_info (char *, int);
static void output_source_filename (const char *, int *);
-static int find_line_common (struct linetable *, int, int *);
+static int find_line_common (struct linetable *, int, int *, int);
static struct symbol *lookup_symbol_aux (const char *name,
const struct block *block,
@@ -147,44 +147,38 @@ multiple_symbols_select_mode (void)
const struct block *block_found;
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
+/* Check for a symtab of a specific name by searching some symtabs.
+ This is a helper function for callbacks of iterate_over_symtabs.
-struct symtab *
-lookup_symtab (const char *name)
+ The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA
+ are identical to the `map_symtabs_matching_filename' method of
+ quick_symbol_functions.
+
+ FIRST and AFTER_LAST indicate the range of symtabs to search.
+ AFTER_LAST is one past the last symtab to search; NULL means to
+ search until the end of the list. */
+
+int
+iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last)
{
- int found;
struct symtab *s = NULL;
- struct objfile *objfile;
- char *real_path = NULL;
- char *full_path = NULL;
struct cleanup *cleanup;
const char* base_name = lbasename (name);
- cleanup = make_cleanup (null_cleanup, NULL);
-
- /* Here we are interested in canonicalizing an absolute path, not
- absolutizing a relative path. */
- if (IS_ABSOLUTE_PATH (name))
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- full_path = xfullpath (name);
- make_cleanup (xfree, full_path);
- real_path = gdb_realpath (name);
- make_cleanup (xfree, real_path);
- }
-
-got_symtab:
-
- /* First, search for an exact match. */
-
- ALL_SYMTABS (objfile, s)
- {
- if (FILENAME_CMP (name, s->filename) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
/* Before we invoke realpath, which can get expensive when many
files are involved, do a quick comparison of the basenames. */
@@ -201,8 +195,8 @@ got_symtab:
if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
{
- do_cleanups (cleanup);
- return s;
+ if (callback (s, data))
+ return 1;
}
}
@@ -216,62 +210,114 @@ got_symtab:
make_cleanup (xfree, rp);
if (FILENAME_CMP (real_path, rp) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
- }
+ }
/* Now, search for a matching tail (only if name doesn't have any dirs). */
if (lbasename (name) == name)
- ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- do_cleanups (cleanup);
- return s;
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
+ return 0;
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work.
+
+ Calls CALLBACK with each symtab that is found and with the supplied
+ DATA. If CALLBACK returns true, the search stops. */
+
+void
+iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data)
+{
+ struct symtab *s = NULL;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ if (iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, NULL))
+ {
+ do_cleanups (cleanups);
+ return;
+ }
+ }
+
/* Same search rules as above apply here, but now we look thru the
psymtabs. */
- found = 0;
ALL_OBJFILES (objfile)
{
if (objfile->sf
- && objfile->sf->qf->lookup_symtab (objfile, name, full_path, real_path,
- &s))
+ && objfile->sf->qf->map_symtabs_matching_filename (objfile,
+ name,
+ full_path,
+ real_path,
+ callback,
+ data))
{
- found = 1;
- break;
+ do_cleanups (cleanups);
+ return;
}
}
- if (s != NULL)
- {
- do_cleanups (cleanup);
- return s;
- }
- if (!found)
- {
- do_cleanups (cleanup);
- return NULL;
- }
+ do_cleanups (cleanups);
+}
+
+/* The callback function used by lookup_symtab. */
- /* At this point, we have located the psymtab for this file, but
- the conversion to a symtab has failed. This usually happens
- when we are looking up an include file. In this case,
- PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
- been created. So, we need to run through the symtabs again in
- order to find the file.
- XXX - This is a crock, and should be fixed inside of the
- symbol parsing routines. */
- goto got_symtab;
+static int
+lookup_symtab_callback (struct symtab *symtab, void *data)
+{
+ struct symtab **result_ptr = data;
+
+ *result_ptr = symtab;
+ return 1;
+}
+
+/* A wrapper for iterate_over_symtabs that returns the first matching
+ symtab, or NULL. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *result = NULL;
+
+ iterate_over_symtabs (name, lookup_symtab_callback, &result);
+ return result;
}
+
\f
/* Mangle a GDB method stub type. This actually reassembles the pieces of the
full method name, which consist of the class name (from T), the unadorned
@@ -1006,33 +1052,16 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
return sym;
}
-/* Find the definition for a specified symbol name NAME
- in domain DOMAIN, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-/* This function has a bunch of loops in it and it would seem to be
- attractive to put in some QUIT's (though I'm not really sure
- whether it can run long enough to be really important). But there
- are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
- that there is C++ code below which can error(), but that probably
- doesn't affect these calls since they are looking for a known
- variable and thus can probably assume it will never hit the C++
- code). */
+/* Compute the demangled form of NAME as used by the various symbol
+ lookup functions. The result is stored in *RESULT_NAME. Returns a
+ cleanup which can be used to clean up the result. */
-struct symbol *
-lookup_symbol_in_language (const char *name, const struct block *block,
- const domain_enum domain, enum language lang,
- int *is_a_field_of_this)
+struct cleanup *
+demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
- struct symbol *returnval;
struct cleanup *cleanup = make_cleanup (null_cleanup, 0);
modified_name = name;
@@ -1079,6 +1108,38 @@ lookup_symbol_in_language (const char *name, const struct block *block,
}
}
+ *result_name = modified_name;
+ return cleanup;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
+
+struct symbol *
+lookup_symbol_in_language (const char *name, const struct block *block,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ const char *modified_name;
+ struct symbol *returnval;
+ struct cleanup *cleanup = demangle_for_lookup (name, lang, &modified_name);
+
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
@@ -1771,6 +1832,44 @@ lookup_block_symbol (const struct block *block, const char *name,
}
}
+/* Iterate over the symbols named NAME, matching DOMAIN, starting with
+ BLOCK.
+
+ For each symbol that matches, CALLBACK is called. The symbol and
+ DATA are passed to the callback.
+
+ If CALLBACK returns zero, the iteration ends. Otherwise, the
+ search continues. This function iterates upward through blocks.
+ When the outermost block has been finished, the function
+ returns. */
+
+void
+iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+ SYMBOL_DOMAIN (sym), domain))
+ {
+ if (!callback (sym, data))
+ return;
+ }
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+}
+
/* Find the symtab associated with PC and SECTION. Look through the
psymtabs and read in another symtab if necessary. */
@@ -2196,7 +2295,7 @@ find_line_symtab (struct symtab *symtab, int line,
/* First try looking it up in the given symtab. */
best_linetable = LINETABLE (symtab);
best_symtab = symtab;
- best_index = find_line_common (best_linetable, line, &exact);
+ best_index = find_line_common (best_linetable, line, &exact, 0);
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
@@ -2241,7 +2340,7 @@ find_line_symtab (struct symtab *symtab, int line,
&& FILENAME_CMP (symtab->fullname, s->fullname) != 0)
continue;
l = LINETABLE (s);
- ind = find_line_common (l, line, &exact);
+ ind = find_line_common (l, line, &exact, 0);
if (ind >= 0)
{
if (exact)
@@ -2272,6 +2371,86 @@ done:
return best_symtab;
}
+
+/* qsort comparison function for use by find_pcs_for_symtab_line. */
+
+static int
+compare_core_addrs (const void *a, const void *b)
+{
+ const CORE_ADDR *ca = a;
+ const CORE_ADDR *cb = b;
+
+ return (int) (ca - cb);
+}
+
+/* Given SYMTAB, return one PC per function in the symtab that exactly
+ matches LINE. Returns NULL if none matched. */
+
+VEC (CORE_ADDR) *
+find_pcs_for_symtab_line (struct symtab *symtab, int line)
+{
+ VEC (CORE_ADDR) *result = NULL;
+ int start = 0, ix;
+ struct symbol *previous_function = NULL;
+
+ /* First, collect all the PCs that are at this line. */
+ while (1)
+ {
+ int was_exact;
+ int idx;
+
+ idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+ if (idx < 0)
+ break;
+
+ if (!was_exact)
+ {
+ if (VEC_empty (CORE_ADDR, result))
+ {
+ /* We only found an inexact match. So, redo the search
+ for the found line. */
+ line = LINETABLE (symtab)->item[idx].line;
+ start = 0;
+ continue;
+ }
+ break;
+ }
+
+ VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+ start = idx + 1;
+ }
+
+ if (VEC_empty (CORE_ADDR, result))
+ return result;
+
+ qsort (VEC_address (CORE_ADDR, result), VEC_length (CORE_ADDR, result),
+ sizeof (CORE_ADDR), compare_core_addrs);
+
+ /* Remove all duplicate entries from the result. That is, each
+ function should only appear a single time. */
+ for (ix = 0; ix < VEC_length (CORE_ADDR, result); )
+ {
+ struct symbol *sym;
+ struct block *block;
+
+ block = block_for_pc (VEC_index (CORE_ADDR, result, ix));
+ sym = block ? block_containing_function (block) : NULL;
+
+ if (sym == NULL || sym == previous_function)
+ VEC_ordered_remove (CORE_ADDR, result, ix);
+ else
+ {
+ previous_function = sym;
+ ++ix;
+ }
+ }
+
+ if (VEC_length (CORE_ADDR, result) == 0)
+ VEC_free (CORE_ADDR, result);
+
+ return result;
+}
+
\f
/* Set the PC value for a given source file and line number and return true.
Returns zero for invalid line number (and sets the PC to 0).
@@ -2340,12 +2519,13 @@ find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr,
/* Given a line table and a line number, return the index into the line
table for the pc of the nearest line whose number is >= the specified one.
Return -1 if none is found. The value is >= 0 if it is an index.
+ START is the index at which to start searching the line table.
Set *EXACT_MATCH nonzero if the value returned is an exact match. */
static int
find_line_common (struct linetable *l, int lineno,
- int *exact_match)
+ int *exact_match, int start)
{
int i;
int len;
@@ -2365,7 +2545,7 @@ find_line_common (struct linetable *l, int lineno,
return -1;
len = l->nitems;
- for (i = 0; i < len; i++)
+ for (i = start; i < len; i++)
{
struct linetable_entry *item = &(l->item[i]);
@@ -4531,8 +4711,7 @@ decode_line_spec (char *string, int funfirstline)
cursal = get_current_source_symtab_and_line ();
sals = decode_line_1 (&string, funfirstline,
- cursal.symtab, cursal.line,
- NULL);
+ cursal.symtab, cursal.line);
if (*string)
error (_("Junk at end of line specification: %s"), string);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 39a61f4..8bc2af9 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -22,6 +22,8 @@
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
+#include "vec.h"
+
/* Opaque declarations. */
struct ui_file;
struct frame_info;
@@ -1056,6 +1058,12 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern void iterate_over_minimal_symbols (struct objfile *objf,
+ const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data);
+
extern int in_gnu_ifunc_stub (CORE_ADDR pc);
/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
@@ -1308,4 +1316,30 @@ struct objfile *lookup_objfile_from_block (const struct block *block);
extern int basenames_may_differ;
+int iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last);
+
+void iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data);
+
+DEF_VEC_I (CORE_ADDR);
+
+VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line);
+
+void iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data);
+
+struct cleanup *demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name);
+
#endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index b653057..65a9b75 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,36 @@
+2011-11-16 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/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.
+
2011-11-15 Paul Koning <paul_koning@dell.com>
* gdb.python/py-type.exp: New testcases for exceptions on scalar
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 8b22324..d3c9cfc 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
- gdb.java gdb.mi gdb.modula2 gdb.multi \
+ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
$(SUBDIRS)
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 82206b3..fb70b3d 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4166,6 +4166,7 @@ do
"gdb.hp/gdb.aCC/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.aCC/Makefile" ;;
"gdb.hp/gdb.compat/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.compat/Makefile" ;;
"gdb.hp/gdb.defects/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.defects/Makefile" ;;
+ "gdb.linespec/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.linespec/Makefile" ;;
"gdb.mi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
"gdb.modula2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.multi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 8631442..121fd37 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -95,7 +95,7 @@ AC_OUTPUT([Makefile \
gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
- gdb.hp/gdb.defects/Makefile \
+ gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \
gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \
diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp
index 92fcc69..c5885ba 100644
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -540,8 +540,9 @@ gdb_test_multiple "catch exec" "$name" {
# Verify that GDB responds gracefully when asked to set a breakpoint
# on a nonexistent source line.
#
+gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in file .*" \
+ "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/list.exp b/gdb/testsuite/gdb.base/list.exp
index 5b9fe15..d4935ee 100644
--- a/gdb/testsuite/gdb.base/list.exp
+++ b/gdb/testsuite/gdb.base/list.exp
@@ -489,7 +489,7 @@ proc test_list_filename_and_function {} {
gdb_test "list foobar.c:main" "No source file named foobar.c.|Location not found" "list filename:function; nonexistant file"
- gdb_test "list list0.h:foobar" "Function \"foobar\" not defined.|Location not found" "list filename:function; nonexistant function"
+ gdb_test "list list0.h:foobar" "Function \"foobar\" not defined in \"list0.h\"." "list filename:function; nonexistant function"
}
diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp
index 1a9072d..bb0b914 100644
--- a/gdb/testsuite/gdb.base/sepdebug.exp
+++ b/gdb/testsuite/gdb.base/sepdebug.exp
@@ -337,7 +337,8 @@ gdb_test_multiple "catch exec" $name {
# on a nonexistent source line.
#
-gdb_test "break 999" "No line 999 in file .*" \
+gdb_test_no_output "set breakpoint pending off"
+gdb_test "break 999" "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index aa723c6..d402ebb 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -46,11 +46,6 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $binfile_lib
-if ![runto_main] then {
- fail "Can't run to main"
- return 0
-}
-
# Set a breakpoint in the binary.
gdb_test "br foo2" \
"Breakpoint.*file.*${testfile}\\.c.*" \
@@ -58,6 +53,11 @@ gdb_test "br foo2" \
delete_breakpoints
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
# Break in the library.
gdb_test "br foo" \
"Breakpoint.*file.*${libname}\\.c.*" \
@@ -67,9 +67,9 @@ gdb_test "continue" \
"Continuing.*" \
"continue"
-# This symbol is now looked up in the ELF library.
+# This symbol is now looked up in the ELF library and the binary.
gdb_test "br foo2" \
- "Breakpoint.*file.*${libname}\\.c.*" \
+ "Breakpoint.*: foo2. .2 locations..*" \
"foo2 in mdlib"
gdb_exit
diff --git a/gdb/testsuite/gdb.base/solib-weak.exp b/gdb/testsuite/gdb.base/solib-weak.exp
index 1f23aa2..52fd72d 100644
--- a/gdb/testsuite/gdb.base/solib-weak.exp
+++ b/gdb/testsuite/gdb.base/solib-weak.exp
@@ -101,15 +101,6 @@ proc do_test { lib1opts lib2opts lib1first } {
gdb_breakpoint "bar"
- # If the library which will be used is compiled without debugging
- # information, GDB will pick the wrong copy of "bar", i.e. the one
- # with debugging information.
-
- if {(${lib1opts} == "" && ${lib2opts} != "" && ${lib1first} == 1)
- || (${lib1opts} != "" && ${lib2opts} == "" && ${lib1first} == 0)} {
- setup_kfail gdb/1824 *-*-*
- }
-
gdb_test "continue" "Breakpoint .* \\.?bar .*${expected_file}\\..*" \
"run to breakpoint - $testopts"
}
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 6a99175..0438424 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -50,13 +50,13 @@ if ![runto_main] then {
# and a condition.
gdb_test "break 'Derived::Derived(int)'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
"set-breakpoint at ctor"
gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
gdb_test "break 'Derived::~Derived()'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
"set-breakpoint at dtor"
gdb_test "continue" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index d670b56..05b378c 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -62,7 +62,7 @@ set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
# Set a breakpoint with multiple locations.
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set breakpoint"
gdb_run_cmd
@@ -128,7 +128,7 @@ if { ![runto_main] } {
}
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 80c080b..933d690 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -52,7 +52,7 @@ set bp_location [gdb_get_line_number "set breakpoint here"]
# and a condition.
gdb_test "break $srcfile:$bp_location if i==1" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"initial condition: set breakpoint"
gdb_run_cmd
@@ -80,7 +80,7 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"separate condition: set breakpoint"
gdb_test_no_output "condition 1 i==1" \
@@ -177,7 +177,7 @@ if { ![runto_main] } {
}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/method2.exp b/gdb/testsuite/gdb.cp/method2.exp
index 2fa4169..29a387d 100644
--- a/gdb/testsuite/gdb.cp/method2.exp
+++ b/gdb/testsuite/gdb.cp/method2.exp
@@ -51,7 +51,7 @@ proc test_break { lang } {
"setting language $lang"
gdb_test_multiple "break A::method" "breaking in method ($lang)" {
- -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. A::method\\(A\\*\\) at .*\[\r\n\]*.3. A::method\\(int\\) at .*\[\r\n\]*\[\r\n\]*.4. A::method\\(\\) at .*\[\r\n\]*> $" {
+ -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. .*:A::method\\(A\\*\\)\[\r\n\]*.3. .*:A::method\\(int\\)\[\r\n\]*.4. .*:A::method\\(\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"breaking in method ($lang)"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index f5d4051..f5b41ab 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -130,18 +130,18 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} {
set menu_overload1arg "\\\[0\\\] cancel\r\n"
append menu_overload1arg "\\\[1\\\] all\r\n"
-append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n"
-append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n"
-append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n"
-append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n"
-append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n"
-append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n"
-append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n"
-append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n"
-append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n"
-append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n"
-append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n"
-append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n"
+append menu_overload1arg "\\\[2\\\] .*$srcfile:foo::overload1arg\\(double\\)\r\n"
+append menu_overload1arg "\\\[3\\\] .*$srcfile:foo::overload1arg\\(float\\)\r\n"
+append menu_overload1arg "\\\[4\\\] .*$srcfile:foo::overload1arg\\((unsigned long|long unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[5\\\] .*$srcfile:foo::overload1arg\\(long( int)?\\)\r\n"
+append menu_overload1arg "\\\[6\\\] .*$srcfile:foo::overload1arg\\((unsigned int|unsigned)\\)\r\n"
+append menu_overload1arg "\\\[7\\\] .*$srcfile:foo::overload1arg\\(int\\)\r\n"
+append menu_overload1arg "\\\[8\\\] .*$srcfile:foo::overload1arg\\((unsigned short|short unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[9\\\] .*$srcfile:foo::overload1arg\\(short( int)?\\)\r\n"
+append menu_overload1arg "\\\[10\\\] .*$srcfile:foo::overload1arg\\(unsigned char\\)\r\n"
+append menu_overload1arg "\\\[11\\\] .*$srcfile:foo::overload1arg\\(signed char\\)\r\n"
+append menu_overload1arg "\\\[12\\\] .*$srcfile:foo::overload1arg\\(char\\)\r\n"
+append menu_overload1arg "\\\[13\\\] .*$srcfile:foo::overload1arg\\((void|)\\)\r\n"
append menu_overload1arg "> $"
# Set multiple-symbols to "ask", to allow us to test the use
@@ -279,7 +279,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $decimal at $hex: file.*$srcfile, line 121.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 120.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 119.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 118.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 117.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 116.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 115.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 114.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 113.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 112.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 111.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 110.\r\nwarning: Multiple breakpoints were set.\r\nUse the .delete. command to delete unwanted breakpoints.\r\n$gdb_prompt $" {
+ -re "Breakpoint $decimal at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -306,18 +306,19 @@ gdb_expect {
gdb_test "info break" \
"Num Type\[\t \]+Disp Enb Address\[\t \]+What.*
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
+\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+<MULTIPLE>\[\t \]*\r
+\[0-9\]+.1\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
+\[0-9\]+.2\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
+\[0-9\]+.3\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
+\[0-9\]+.4\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
+\[0-9\]+.5\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
+\[0-9\]+.6\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
+\[0-9\]+.7\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
+\[0-9\]+.8\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
+\[0-9\]+.9\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
+\[0-9\]+.10\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
+\[0-9\]+.11\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
+\[0-9\]+.12\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
"breakpoint info (after setting on all)"
@@ -333,10 +334,10 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
send_gdb "continue\n"
gdb_expect {
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
pass "continue to bp overloaded : ${argtype}"
}
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
if $might_kfail {
kfail "gdb/1025" "continue to bp overloaded : ${argtype}"
} else {
@@ -352,17 +353,17 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
}
}
-continue_to_bp_overloaded 0 25 "(void|)" ""
-continue_to_bp_overloaded 1 24 "char" "arg=2 \\'\\\\002\\'"
-continue_to_bp_overloaded 1 23 "signed char" "arg=3 \\'\\\\003\\'"
-continue_to_bp_overloaded 1 22 "unsigned char" "arg=4 \\'\\\\004\\'"
-continue_to_bp_overloaded 1 21 "short" "arg=5"
-continue_to_bp_overloaded 1 20 "unsigned short" "arg=6"
-continue_to_bp_overloaded 0 19 "int" "arg=7"
-continue_to_bp_overloaded 0 18 "(unsigned|unsigned int)" "arg=8"
-continue_to_bp_overloaded 0 17 "long" "arg=9"
-continue_to_bp_overloaded 0 16 "unsigned long" "arg=10"
-continue_to_bp_overloaded 0 15 "float" "arg=100"
+continue_to_bp_overloaded 0 14 "(void|)" ""
+continue_to_bp_overloaded 1 14 "char" "arg=2 \\'\\\\002\\'"
+continue_to_bp_overloaded 1 14 "signed char" "arg=3 \\'\\\\003\\'"
+continue_to_bp_overloaded 1 14 "unsigned char" "arg=4 \\'\\\\004\\'"
+continue_to_bp_overloaded 1 14 "short" "arg=5"
+continue_to_bp_overloaded 1 14 "unsigned short" "arg=6"
+continue_to_bp_overloaded 0 14 "int" "arg=7"
+continue_to_bp_overloaded 0 14 "(unsigned|unsigned int)" "arg=8"
+continue_to_bp_overloaded 0 14 "long" "arg=9"
+continue_to_bp_overloaded 0 14 "unsigned long" "arg=10"
+continue_to_bp_overloaded 0 14 "float" "arg=100"
continue_to_bp_overloaded 1 14 "double" "arg=200"
# Test breaking on an overloaded function when multiple-symbols
@@ -375,7 +376,7 @@ gdb_test "break foo::foofunc" \
# is set to "all"
gdb_test_no_output "set multiple-symbols all"
gdb_test "break foo::foofunc" \
- "Breakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nBreakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nwarning: Multiple breakpoints were set\\.\r\nUse the \"delete\" command to delete unwanted breakpoints\\."
+ "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*"
# That's all, folks.
diff --git a/gdb/testsuite/gdb.cp/ovsrch.exp b/gdb/testsuite/gdb.cp/ovsrch.exp
index b509a25..3c3fd29 100644
--- a/gdb/testsuite/gdb.cp/ovsrch.exp
+++ b/gdb/testsuite/gdb.cp/ovsrch.exp
@@ -73,28 +73,28 @@ if {![runto_main]} {
}
# Break in A::stop_here and run tests.
-if {[gdb_breakpoint "stop_here"]} {
- pass "break stop_here"
+if {[gdb_breakpoint "A::stop_here"]} {
+ pass "break A::stop_here"
}
-if {[gdb_breakpoint "'stop_here'"]} {
- pass "break 'stop_here'"
+if {[gdb_breakpoint "'A::stop_here'"]} {
+ pass "break 'A::stop_here'"
}
gdb_continue_to_breakpoint "stop_here"
-test_class outer
+test_class A::outer
# Break in A::B::stop_here_too and run tests.
-if {[gdb_breakpoint "B::stop_here_too"]} {
- pass "break B::stop_here_too"
+if {[gdb_breakpoint "A::B::stop_here_too"]} {
+ pass "break A::B::stop_here_too"
}
-if {[gdb_breakpoint "'B::stop_here_too'"]} {
- pass "break 'B::stop_here_too'"
+if {[gdb_breakpoint "'A::B::stop_here_too'"]} {
+ pass "break 'A::B::stop_here_too'"
}
gdb_continue_to_breakpoint "stop_here_too"
-test_class inner
+test_class A::B::inner
gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.cp/re-set-overloaded.exp b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
index 2052552..bd5f3ba 100644
--- a/gdb/testsuite/gdb.cp/re-set-overloaded.exp
+++ b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
@@ -46,7 +46,6 @@ gdb_test_no_output {set variable $brk = $bpnum}
# runto or runto_main would call delete_breakpoints.
gdb_breakpoint "main"
gdb_run_cmd
-setup_kfail breakpoints/11657 *-*-*
gdb_test "" ".*" "start"
set test "breakpoint resolved"
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 6612b4a..9b1ae37 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -109,12 +109,7 @@ proc test_template_breakpoints {} {
global hp_aCC_compiler
gdb_test_multiple "break T5<int>::T5" "constructor breakpoint" {
- -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5<int>::T5\\(int\\) at .*\[\r\n\]*.3. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*\[\r\n\]*> $" {
- gdb_test "0" \
- "canceled" \
- "constructor breakpoint (obsolete format!)"
- }
- -re ".0. cancel\[\r\n\]*.1. all\[\r\n\]*.2. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*templates.cc:.*\[\r\n\]*.3. T5<int>::T5\\(int\\) at .*templates.cc:.*\[\r\n\]*> $" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\)\[\r\n\]*.3.*templates.cc:T5<int>::T5\\(int\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"constructor breakpoint"
@@ -153,7 +148,7 @@ proc test_template_breakpoints {} {
set bp_location [gdb_get_line_number \
"set breakpoint on a line with no real code"]
gdb_test "break ${testfile}.cc:${bp_location}" \
- "Breakpoint.*at.* file .*${testfile}.cc, line.*(2 locations).*" \
+ "Breakpoint.*at.*: .*${testfile}.cc:${bp_location}.*(2 locations).*" \
"breakpoint on a line with no real code"
delete_breakpoints
}
diff --git a/gdb/testsuite/gdb.linespec/Makefile.in b/gdb/testsuite/gdb.linespec/Makefile.in
new file mode 100644
index 0000000..2658a24
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/Makefile.in
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = lspec
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
new file mode 100644
index 0000000..882ccc9
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+
+
+
+
+
+int m(int x)
+{
+ return x + 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(int x)
+{
+ return x + 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
new file mode 100644
index 0000000..43917f8
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
@@ -0,0 +1,19 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#include "../../lspec.h"
+
+static int dupname(int y)
+{
+ label: return y;
+}
+
+int n(int y)
+{
+ return dupname(y) - 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(double x)
+{
+ return (int) x - 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
new file mode 100644
index 0000000..122a468
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -0,0 +1,106 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of ambiguous linespecs.
+
+set testfile linespec
+
+set exefile lspec
+set binfile ${objdir}/${subdir}/${exefile}
+
+set baseone base/one/thefile.cc
+set basetwo base/two/thefile.cc
+
+set hex {0x[0-9a-fA-F]+}
+
+if {[skip_cplus_tests]} {
+ unsupported linespec.exp
+ return
+}
+
+if {[prepare_for_testing ${testfile}.exp $exefile \
+ [list lspec.cc $baseone $basetwo] \
+ {debug nowarnings}]} {
+ return -1
+}
+
+gdb_test_no_output "set multiple-symbols all" \
+ "set multiple-symbols to all for linespec tests"
+
+set l1 [gdb_get_line_number "thefile breakpoint" $baseone]
+set l2 [gdb_get_line_number "thefile breakpoint" $basetwo]
+
+if {$l1 != $l2} {
+ error "somebody incompatibly modified the source files needed by linespec.exp"
+}
+
+gdb_test "break thefile.cc:$l1" \
+ "Breakpoint 1 at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
+ "multi-location break using file:line"
+
+# We'd like this to work, but it currently does not.
+# gdb_test "break one/thefile.cc:$l1"
+
+gdb_test "break dupname" \
+ "Breakpoint 2 at $hex: dupname. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name"
+
+gdb_test "break dupname:label" \
+ "Breakpoint 3 at $hex: dupname:label. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name and label"
+
+gdb_test_no_output "set breakpoint pending off" \
+ "disable pending breakpoints for linespec tests"
+
+# This is PR breakpoints/12856.
+gdb_test "break lspec.cc:nosuchfunction" \
+ "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
+ "set breakpoint on non-existent function"
+
+gdb_test "break NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
+ "set breakpoint at all instances of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at lspec.cc instance of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload(double)" \
+ "Function \"NameSpace::overload\\(double\\)\" not defined in \"lspec.cc\"." \
+ "set breakpoint at non-existent lspec.cc instance of NameSpace::overload"
+
+gdb_test "break NameSpace::overload()" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at specific instance of NameSpace::overload"
+
+#
+# Multi-inferior tests.
+#
+
+gdb_test "add-inferior" "Added inferior 2" \
+ "add inferior for linespec tests"
+
+gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch to inferior 2 for linespec tests"
+
+# Note that in particular this should not cause errors when re-setting
+# breakpoints.
+gdb_test "file $binfile" \
+ "Reading symbols from .*done." \
+ "set the new inferior file for linespec tests"
+
+gdb_test "break main" \
+ "Breakpoint \[0-9\]+ at $hex: main. .2 locations." \
+ "set breakpoint at main in both inferiors"
diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc
new file mode 100644
index 0000000..42e382f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.cc
@@ -0,0 +1,13 @@
+#include "lspec.h"
+
+static int dupname (int x) { label: return x; }
+
+int NameSpace::overload()
+{
+ return 23;
+}
+
+int main()
+{
+ return dupname(0) + m(0) + n(0);
+}
diff --git a/gdb/testsuite/gdb.linespec/lspec.h b/gdb/testsuite/gdb.linespec/lspec.h
new file mode 100644
index 0000000..e4bfc00
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.h
@@ -0,0 +1,9 @@
+extern int m(int x);
+extern int n(int y);
+
+namespace NameSpace {
+ int overload ();
+ int overload (int);
+ int overload (double);
+};
+
diff --git a/gdb/testsuite/gdb.objc/objcdecode.exp b/gdb/testsuite/gdb.objc/objcdecode.exp
index 720bfd8..e3916f6 100644
--- a/gdb/testsuite/gdb.objc/objcdecode.exp
+++ b/gdb/testsuite/gdb.objc/objcdecode.exp
@@ -52,17 +52,19 @@ proc do_objc_tests {} {
do_objc_tests
+gdb_test_no_output "set multiple-symbols ask"
+
#
# Break on multiply defined method (PR objc/1236)
#
set name "break on multiply defined method"
gdb_test_multiple "break multipleDef" $name \
{
- -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] -.Decode multipleDef. at .*\r\n\\\[3\\\] multipleDef at .*\r\n> $" {
+ -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] .*${srcfile}:-.Decode multipleDef.\r\n\\\[3\\\] .*${srcfile}:multipleDef\r\n> $" {
send_gdb "3\n"
exp_continue
}
- -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*\r\n$gdb_prompt $" { pass $name }
+ -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: .*\r\n$gdb_prompt $" { pass $name }
-re ".*$gdb_prompt $" { kfail "gdb/1236" $name }
}
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 679cc32..89a2e24 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -74,6 +74,7 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline2" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
+gdb_test_no_output "set breakpoint pending off"
gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
@@ -81,7 +82,6 @@ gdb_test "info trace" "No tracepoints.*" \
# 1.3 trace line in invalid source file
gdb_delete_tracepoints
-gdb_test_no_output "set breakpoint pending off"
gdb_test "trace NoSuChFiLe.c:1" "No source file named NoSuChFiLe.c." \
"1.3a: trace invalid source file"
gdb_test "info trace" "No tracepoints.*" \
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index e155515..035611e 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2449,7 +2449,7 @@ scope_info (char *args, int from_tty)
error (_("requires an argument (function, "
"line or *addr) to define a scope"));
- sals = decode_line_1 (&args, 1, NULL, 0, NULL);
+ sals = decode_line_1 (&args, 1, NULL, 0);
if (sals.nelts == 0)
return; /* Presumably decode_line_1 has already warned. */
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 4c8658d..9b936e1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -455,29 +455,34 @@ tui_update_breakpoint_info (struct tui_win_info *win,
bp != (struct breakpoint *) NULL;
bp = bp->next)
{
+ struct bp_location *loc;
+
gdb_assert (line->line_or_addr.loa == LOA_LINE
|| line->line_or_addr.loa == LOA_ADDRESS);
- if ((win == TUI_SRC_WIN
- && bp->source_file
- && (filename_cmp (src->filename, bp->source_file) == 0)
- && line->line_or_addr.loa == LOA_LINE
- && bp->line_number == line->line_or_addr.u.line_no)
- || (win == TUI_DISASM_WIN
- && line->line_or_addr.loa == LOA_ADDRESS
- && bp->loc != NULL
- && bp->loc->address == line->line_or_addr.u.addr))
- {
- if (bp->enable_state == bp_disabled)
- mode |= TUI_BP_DISABLED;
- else
- mode |= TUI_BP_ENABLED;
- if (bp->hit_count)
- mode |= TUI_BP_HIT;
- if (bp->loc->cond)
- mode |= TUI_BP_CONDITIONAL;
- if (bp->type == bp_hardware_breakpoint)
- mode |= TUI_BP_HARDWARE;
- }
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && loc->source_file
+ && (filename_cmp (src->filename, loc->source_file) == 0)
+ && line->line_or_addr.loa == LOA_LINE
+ && loc->line_number == line->line_or_addr.u.line_no)
+ || (win == TUI_DISASM_WIN
+ && line->line_or_addr.loa == LOA_ADDRESS
+ && loc->address == line->line_or_addr.u.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->loc->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
}
if (line->has_break != mode)
{
diff --git a/gdb/utils.c b/gdb/utils.c
index 82a0f45..81a8463 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3650,6 +3650,17 @@ compare_positive_ints (const void *ap, const void *bp)
return * (int *) ap - * (int *) bp;
}
+/* String compare function for qsort. */
+
+int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+
+ return strcmp (*s1, *s2);
+}
+
#define AMBIGUOUS_MESS1 ".\nMatching formats:"
#define AMBIGUOUS_MESS2 \
".\nUse \"set gnutarget format-name\" to specify the format."
--
1.7.6.4
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: doc changes --]
[-- Type: text/x-patch, Size: 2805 bytes --]
From 7ab317d5f4d9ef1d4ed52693f916f191fd2de1b1 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Mon, 14 Nov 2011 13:18:19 -0700
Subject: [PATCH 4/4] doc changes
---
gdb/ChangeLog | 4 ++++
gdb/NEWS | 6 ++++++
gdb/doc/ChangeLog | 4 ++++
gdb/doc/gdb.texinfo | 9 ++++-----
4 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7abd7ef..b4b3f4b 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,9 @@
2011-11-16 Tom Tromey <tromey@redhat.com>
+ * NEWS: Document ambiguous linespec change.
+
+2011-11-16 Tom Tromey <tromey@redhat.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,
diff --git a/gdb/NEWS b/gdb/NEWS
index c4e59c4..4605abd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,12 @@
*** Changes since GDB 7.3.1
+* GDB now handles ambiguous linespecs more consistently; the existing
+ FILE:LINE support has been expanded to other types of linespecs. A
+ breakpoint will now be set on all matching locations in all
+ inferiors, and locations will be added or removed according to
+ inferior changes.
+
* GDB now allows you to skip uninteresting functions and files when
stepping with the "skip function" and "skip file" commands.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 4975cd2..947a5d0 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2011-11-16 Tom Tromey <tromey@redhat.com>
+
+ * gdb.texinfo (Set Breaks): Update for new behavior.
+
2011-11-15 Doug Evans <dje@google.com>
* gdb.texinfo (Files): Document basenames-may-differ.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f4f7f1e..1b01e19 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3522,6 +3522,9 @@ in your program. Examples of this situation are:
@itemize @bullet
@item
+Multiple functions in the program may have the same name.
+
+@item
For a C@t{++} constructor, the @value{NGCC} compiler generates several
instances of the function body, used in different cases.
@@ -3535,11 +3538,7 @@ several places where that function is inlined.
@end itemize
In all those cases, @value{GDBN} will insert a breakpoint at all
-the relevant locations@footnote{
-As of this writing, multiple-location breakpoints work only if there's
-line number information for all the locations. This means that they
-will generally not work in system libraries, unless you have debug
-info with line numbers for them.}.
+the relevant locations.
A breakpoint with multiple locations is displayed in the breakpoint
table using several rows---one header row, followed by one row for
--
1.7.6.4
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 15:43 ` Yao Qi
@ 2011-11-16 16:11 ` Tom Tromey
2011-11-16 16:44 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 16:11 UTC (permalink / raw)
To: Yao Qi; +Cc: Jan Kratochvil, gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> +FAIL: gdb.cp/ovsrch.exp: break A::B::inner::foo if (a == 3)
Yao> I'll debug this problem tomorrow, but if you have any clues, that will
Yao> be helpful.
What is mysterious is that I do not see this failure.
I actually think this test should fail, because it is applying a
condition in a scope where there is no variable 'a'.
I will debug it today.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 8:15 ` Yao Qi
@ 2011-11-16 16:17 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 16:17 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
Yao> Thanks to Doug, I applied your patch on GDB CVS 2011-11-10. My comments
Yao> below,
Oops, sorry, I did not notice this before my rebase.
I will fix up my branch now.
Yao> I suggest that we add a comment, I steal from Ulrich's comment :)
Yao> /* We fall back to GDBARCH if there is no architecture
Yao> associated with SAL. */
Done.
Yao> I got a compilation warning below, and looks like copy_arg should be
Yao> initialized to NULL.
Done.
>> - /* Ranged breakpoints have only one start location and one end location. */
>> - gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
>> + if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
>> + {
>> + /* Ranged breakpoints have only one start location and one end
>> + location. */
>> + b->enable_state = bp_disabled;
>> + update_global_location_list (1);
>> + printf_unfiltered (_("Could not reset ranged breakpoint %d: "
>> + "multiple locations found\n"),
>> + b->number);
>> + return;
>> + }
>>
Yao> I don't understand why assert is replaced by a condition check.
Yao> Could you elaborate a little?
There was a thread on gdb@ about this.
Anyway, this is a bad assert. If breakpoint re-setting causes a ranged
breakpoint to have multiple locations -- which is possible today if you
use "file:line" breakpoints -- then gdb will crash.
On the gdb thread we agreed to disable the ranged breakpoint in this
situation.
Yao> ${hex} has been defined in dejagnu/runtest.exp, and we can simply
Yao> use it.
Thanks, fixed.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 14:54 ` Tom Tromey
@ 2011-11-16 16:32 ` Doug Evans
2011-11-16 16:39 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Doug Evans @ 2011-11-16 16:32 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On Wed, Nov 16, 2011 at 6:54 AM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> "Doug" == Doug Evans <dje@google.com> writes:
>
> Doug> Another question while we're cleaning up linespecs, if I may.
> Doug> The docs have this:
>
> Doug> @item '@var{filename}'::@var{funcaddr}
> Doug> Like @var{funcaddr} above, but also specifies the name of the source
> Doug> file explicitly. This is useful if the name of the function does not
> Doug> specify the function unambiguously, e.g., if there are several
> Doug> functions with identical names in different source files.
>
> Doug> Is the double colon, ::, a typo? I've only ever seen filename
> Doug> delimited with a single colon.
>
> This form is only valid for expressions, that is, if you type
>
> break *'file.c'::function
>
> This is a syntax extension that gdb provides. See the 'block'
> production in c-exp.y.
Sigh. :-(
> Doug> I'm hoping we can trivially decide that a file name is present by
> Doug> seeing a single colon.
>
> In general I agree, but there are some corner cases to consider.
>
> There's the easy(-ish) corner case of DOS file names:
>
> break c:/file.c:function
>
> There's also an Objective C case where a trailing ":" is part of the
> function name. I forget the exact syntax, maybe it can only appear in
> brackets:
>
> break +[method:]
I don't mind having code to catch these.
They're not normal file names.
> Anyway, like I said in the previous thread, in my view, gdb should
> require quoting for all unusual file names. We should try to be
> compatible, but we don't have to try too awfully hard, since a lot of
> things never worked anyway.
It's not clear that the result of this is that we can programmatically
determine if a file name is present without having to go see if it's
present in the debug info.
Did you have something in mind?
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 16:32 ` Doug Evans
@ 2011-11-16 16:39 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 16:39 UTC (permalink / raw)
To: Doug Evans; +Cc: Jan Kratochvil, gdb-patches
>>>>> "Doug" == Doug Evans <dje@google.com> writes:
Doug> It's not clear that the result of this is that we can programmatically
Doug> determine if a file name is present without having to go see if it's
Doug> present in the debug info.
Doug> Did you have something in mind?
Yeah, I don't think that is possible. I think all you can do without
digging around is perhaps split the linespec into tokens. Otherwise you
have to deal with cases like "FUNCTION:LABEL" differently; and proposed
syntax like an optional "OBJFILE:" prefix no longer makes sense.
If you are looking for some kind of precision in specifying linespecs, I
think implementing an argument form would be more fruitful:
break -objfile O -file F.c -function F
Then one can write exactly what one means in the situations that require
it.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 16:11 ` Tom Tromey
@ 2011-11-16 16:44 ` Tom Tromey
2011-11-17 3:49 ` Yao Qi
0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-11-16 16:44 UTC (permalink / raw)
To: Yao Qi; +Cc: Jan Kratochvil, gdb-patches
Yao> I'll debug this problem tomorrow, but if you have any clues, that will
Yao> be helpful.
Tom> What is mysterious is that I do not see this failure.
Tom> I actually think this test should fail, because it is applying a
Tom> condition in a scope where there is no variable 'a'.
Tom> I will debug it today.
Ok, I found the problem. "a" is defined in a system library for which I
have debuginfo installed:
(top-gdb) p *sym.symtab
$22 = {
[...]
filename = 0x26ba950 "../sysdeps/ieee754/dbl-64/atnat.h",
dirname = 0x26c4f10 "/usr/src/debug/glibc-2.14-34-ge2a3090/math",
So the condition erroneously parses.
Changing the names to "a_param" instead makes it fail again.
I think the test is bogus, though, so I changed it in a way that will
make it succeed.
I can send a new revision of everything if you want.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-15 16:30 ` Tom Tromey
2011-11-15 16:59 ` Pierre Muller
2011-11-16 0:09 ` Jan Kratochvil
@ 2011-11-16 21:23 ` Stan Shebs
2 siblings, 0 replies; 42+ messages in thread
From: Stan Shebs @ 2011-11-16 21:23 UTC (permalink / raw)
To: gdb-patches
On 11/15/11 8:30 AM, Tom Tromey wrote:
>>>>>> "Tom" == Tom Tromey<tromey@redhat.com> writes:
> Tom> I plan to commit this sometime this week, barring objections or
> Tom> comments; after the doc patch (forthcoming) is approved.
>
> I'm having second thoughts about this. Today it seems slightly crazy to
> check in such a huge patch just before a release. Any other thoughts on
> this?
>
> Tom
>
One of the advantages of hacking on GDB vs GCC is that GDB degrades more
gracefully; it's rare for a GDB patch to completely break debugging,
while an innocent-looking GCC patch can bring the whole house of cards
down. Plus, we
don't have any dependencies pushing us to release on a particular date,
right? So I tend to think this would be OK for 7.4.
Stan
stan@codesourcery.com
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 16:44 ` Tom Tromey
@ 2011-11-17 3:49 ` Yao Qi
2011-11-21 21:50 ` Tom Tromey
0 siblings, 1 reply; 42+ messages in thread
From: Yao Qi @ 2011-11-17 3:49 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On 11/17/2011 12:44 AM, Tom Tromey wrote:
> Yao> I'll debug this problem tomorrow, but if you have any clues, that will
> Yao> be helpful.
>
> Tom> What is mysterious is that I do not see this failure.
> Tom> I actually think this test should fail, because it is applying a
> Tom> condition in a scope where there is no variable 'a'.
>
> Tom> I will debug it today.
>
> Ok, I found the problem. "a" is defined in a system library for which I
> have debuginfo installed:
>
> (top-gdb) p *sym.symtab
OOC, could you give me a stack backtrace here?
> $22 = {
> [...]
> filename = 0x26ba950 "../sysdeps/ieee754/dbl-64/atnat.h",
> dirname = 0x26c4f10 "/usr/src/debug/glibc-2.14-34-ge2a3090/math",
>
> So the condition erroneously parses.
>
That is great!
> Changing the names to "a_param" instead makes it fail again.
>
> I think the test is bogus, though, so I changed it in a way that will
> make it succeed.
>
Agreed.
> I can send a new revision of everything if you want.
No, I don't.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-16 14:46 ` Tom Tromey
@ 2011-11-18 14:10 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-18 14:10 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
Jan> Still more time could give more reviews, for whatever reason I for
Jan> example haven't yet run a regression test on `break'ing on all
Jan> symbols of Fedora .debug files which found regressions in Keith's
Jan> patchset, also I haven't yet found energy for the full review for
Jan> whatever reason.
Tom> I'll try this test against the debuginfo I have installed here.
I ran it against a big C++ library, libwebkitgtk. This took long enough
that I don't think I want to run it against everything.
This revealed one pre-existing bug, but nothing specific to my patch:
http://sourceware.org/bugzilla/show_bug.cgi?id=13417
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-17 3:49 ` Yao Qi
@ 2011-11-21 21:50 ` Tom Tromey
0 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-21 21:50 UTC (permalink / raw)
To: Yao Qi; +Cc: Jan Kratochvil, gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
>> (top-gdb) p *sym.symtab
Yao> OOC, could you give me a stack backtrace here?
Sorry, the session is long gone. Basically I stopped in parse_exp_1,
continued until for the parsing happened for the "bad" location, then
stepped through lookup_symbol_in_language to see how gdb was resolving
'a'.
Tom
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: RFA: implement ambiguous linespec proposal
2011-11-14 21:11 ` Tom Tromey
` (4 preceding siblings ...)
2011-11-16 15:43 ` Yao Qi
@ 2011-11-23 21:33 ` Tom Tromey
5 siblings, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-11-23 21:33 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Tom> Here is the final revision.
One more revision, probably not final.
I'm sending it because Joel wanted to try things, and he needed a
refresh.
This one implements the heuristic I mentioned in my earlier email.
I also added some tests and fixed up a call to get_selected_block in
linespec (this is not ok due to language switching, see get_search_block).
Tom
2011-11-18 Tom Tromey <tromey@redhat.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.
* 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.
* 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.
(compare_core_addrs, find_pcs_for_symtab_line): New functions.
(find_line_common): Add 'start' argument.
(decode_line_spec): Update.
(validate_inexact_match): New function.
* 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.
* source.c (line_info): Set pspace on sal. Check program space in
the loop.
* 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 (struct linespec_sals): New type.
(struct linespec_result) <canonical>: Remove.
<pre_expanded, addr_string, sals>: New fields.
(destroy_linespec_result, make_cleanup_destroy_linespec_result)
(decode_line_list, 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, decode_line_list): 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. Fall back on
decode_variable.
(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.
* 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. 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.
(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.
* block.h (block_containing_function): Declare.
* block.c (block_containing_function): New function.
* skip.c (skip_function_command): Update.
(skip_re_set): Update.
2011-11-18 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.
diff --git a/gdb/block.c b/gdb/block.c
index c165bc2..1fa3688 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -82,6 +82,20 @@ block_linkage_function (const struct block *bl)
return BLOCK_FUNCTION (bl);
}
+/* Return the symbol for the function which contains a specified
+ block, described by a struct block BL. The return value will be
+ the closest enclosing function, which might be an inline
+ function. */
+
+struct symbol *
+block_containing_function (const struct block *bl)
+{
+ while (BLOCK_FUNCTION (bl) == NULL && BLOCK_SUPERBLOCK (bl) != NULL)
+ bl = BLOCK_SUPERBLOCK (bl);
+
+ return BLOCK_FUNCTION (bl);
+}
+
/* Return one if BL represents an inlined function. */
int
diff --git a/gdb/block.h b/gdb/block.h
index 1742f24..63b18a6 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -131,6 +131,8 @@ struct blockvector
extern struct symbol *block_linkage_function (const struct block *);
+extern struct symbol *block_containing_function (const struct block *);
+
extern int block_inlined_p (const struct block *block);
extern int contained_in (const struct block *, const struct block *);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ce9e836..5a463f0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4550,7 +4550,7 @@ print_breakpoint_location (struct breakpoint *b,
if (b->display_canonical)
ui_out_field_string (uiout, "what", b->addr_string);
- else if (b->source_file && loc)
+ else if (loc && loc->source_file)
{
struct symbol *sym
= find_pc_sect_function (loc->address, loc->section);
@@ -4563,7 +4563,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_wrap_hint (uiout, wrap_indent_at_field (uiout, "what"));
ui_out_text (uiout, "at ");
}
- ui_out_field_string (uiout, "file", b->source_file);
+ ui_out_field_string (uiout, "file", loc->source_file);
ui_out_text (uiout, ":");
if (ui_out_is_mi_like_p (uiout))
@@ -4575,7 +4575,7 @@ print_breakpoint_location (struct breakpoint *b,
ui_out_field_string (uiout, "fullname", fullname);
}
- ui_out_field_int (uiout, "line", b->line_number);
+ ui_out_field_int (uiout, "line", loc->line_number);
}
else if (loc)
{
@@ -5798,12 +5798,6 @@ init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
if (bptype != bp_breakpoint && bptype != bp_hardware_breakpoint)
b->pspace = sal.pspace;
- if (sal.symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sal.symtab->filename);
- b->line_number = sal.line;
-
breakpoints_changed ();
}
@@ -6999,12 +6993,10 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
- if (orig->source_file == NULL)
- copy->source_file = NULL;
- else
- copy->source_file = xstrdup (orig->source_file);
+ if (orig->loc->source_file != NULL)
+ copy->loc->source_file = xstrdup (orig->loc->source_file);
- copy->line_number = orig->line_number;
+ copy->loc->line_number = orig->loc->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
copy->pspace = orig->pspace;
@@ -7088,6 +7080,11 @@ add_location_to_breakpoint (struct breakpoint *b,
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
+
+ if (sal->symtab != NULL)
+ loc->source_file = xstrdup (sal->symtab->filename);
+ loc->line_number = sal->line;
+
set_breakpoint_location_function (loc,
sal->explicit_pc || sal->explicit_line);
return loc;
@@ -7144,7 +7141,7 @@ bp_loc_is_permanent (struct bp_location *loc)
static void
init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7258,12 +7255,13 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
me. */
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->filter = filter;
}
static void
create_breakpoint_sal (struct gdbarch *gdbarch,
struct symtabs_and_lines sals, char *addr_string,
- char *cond_string,
+ char *filter, char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
const struct breakpoint_ops *ops, int from_tty,
@@ -7286,7 +7284,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
init_breakpoint_sal (b, gdbarch,
sals, addr_string,
- cond_string,
+ filter, cond_string,
type, disposition,
thread, task, ignore_count,
ops, from_tty,
@@ -7296,138 +7294,6 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
install_breakpoint (internal, b, 0);
}
-/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
- elements to fill the void space. */
-static void
-remove_sal (struct symtabs_and_lines *sal, int index_to_remove)
-{
- int i = index_to_remove+1;
- int last_index = sal->nelts-1;
-
- for (;i <= last_index; ++i)
- sal->sals[i-1] = sal->sals[i];
-
- --(sal->nelts);
-}
-
-/* If appropriate, obtains all sals that correspond to the same file
- and line as SAL, in all program spaces. Users debugging with IDEs,
- will want to set a breakpoint at foo.c:line, and not really care
- about program spaces. This is done only if SAL does not have
- explicit PC and has line and file information. If we got just a
- single expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out all sals for
- which the name of enclosing function is different from SAL. This
- makes sure that if we have breakpoint originally set in template
- instantiation, say foo<int>(), we won't expand SAL to locations at
- the same line in all existing instantiations of 'foo'. */
-
-static struct symtabs_and_lines
-expand_line_sal_maybe (struct symtab_and_line sal)
-{
- struct symtabs_and_lines expanded;
- CORE_ADDR original_pc = sal.pc;
- char *original_function = NULL;
- int found;
- int i;
- struct cleanup *old_chain;
-
- /* If we have explicit pc, don't expand.
- If we have no line number, we can't expand. */
- if (sal.explicit_pc || sal.line == 0 || sal.symtab == NULL)
- {
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sal;
- return expanded;
- }
-
- sal.pc = 0;
-
- old_chain = save_current_space_and_thread ();
-
- switch_to_program_space_and_thread (sal.pspace);
-
- find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
- /* Note that expand_line_sal visits *all* program spaces. */
- expanded = expand_line_sal (sal);
-
- if (expanded.nelts == 1)
- {
- /* We had one sal, we got one sal. Return that sal, adjusting it
- past the function prologue if necessary. */
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- skip_prologue_sal (&expanded.sals[0]);
- do_cleanups (old_chain);
- return expanded;
- }
-
- if (!sal.explicit_line)
- {
- CORE_ADDR func_addr, func_end;
- for (i = 0; i < expanded.nelts; ++i)
- {
- CORE_ADDR pc = expanded.sals[i].pc;
- char *this_function;
-
- /* We need to switch threads as well since we're about to
- read memory. */
- switch_to_program_space_and_thread (expanded.sals[i].pspace);
-
- if (find_pc_partial_function (pc, &this_function,
- &func_addr, &func_end))
- {
- if (this_function
- && strcmp (this_function, original_function) != 0)
- {
- remove_sal (&expanded, i);
- --i;
- }
- }
- }
- }
-
- /* Skip the function prologue if necessary. */
- for (i = 0; i < expanded.nelts; ++i)
- skip_prologue_sal (&expanded.sals[i]);
-
- do_cleanups (old_chain);
-
- if (expanded.nelts <= 1)
- {
- /* This is an ugly workaround. If we get zero expanded sals
- then something is really wrong. Fix that by returning the
- original sal. */
-
- xfree (expanded.sals);
- expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- sal.pc = original_pc;
- expanded.sals[0] = sal;
- return expanded;
- }
-
- if (original_pc)
- {
- found = 0;
- for (i = 0; i < expanded.nelts; ++i)
- if (expanded.sals[i].pc == original_pc)
- {
- found = 1;
- break;
- }
- gdb_assert (found);
- }
-
- return expanded;
-}
-
/* Add SALS.nelts breakpoints to the breakpoint table. For each
SALS.sal[i] breakpoint, include the corresponding ADDR_STRING[i]
value. COND_STRING, if not NULL, specified the condition to be
@@ -7445,7 +7311,6 @@ expand_line_sal_maybe (struct symtab_and_line sal)
static void
create_breakpoints_sal (struct gdbarch *gdbarch,
- struct symtabs_and_lines sals,
struct linespec_result *canonical,
char *cond_string,
enum bptype type, enum bpdisp disposition,
@@ -7454,17 +7319,30 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
int enabled, int internal)
{
int i;
+ struct linespec_sals *lsal;
- for (i = 0; i < sals.nelts; ++i)
+ if (canonical->pre_expanded)
+ gdb_assert (VEC_length (linespec_sals, canonical->sals) == 1);
+
+ for (i = 0; VEC_iterate (linespec_sals, canonical->sals, i, lsal); ++i)
{
- struct symtabs_and_lines expanded =
- expand_line_sal_maybe (sals.sals[i]);
+ /* Note that 'addr_string' can be NULL in the case of a plain
+ 'break', without arguments. */
+ char *addr_string = (canonical->addr_string
+ ? xstrdup (canonical->addr_string)
+ : NULL);
+ char *filter_string = lsal->canonical ? xstrdup (lsal->canonical) : NULL;
+ struct cleanup *inner = make_cleanup (xfree, addr_string);
- create_breakpoint_sal (gdbarch, expanded, canonical->canonical[i],
+ make_cleanup (xfree, filter_string);
+ create_breakpoint_sal (gdbarch, lsal->sals,
+ addr_string,
+ filter_string,
cond_string, type, disposition,
thread, task, ignore_count, ops,
from_tty, enabled, internal,
canonical->special_display);
+ discard_cleanups (inner);
}
}
@@ -7478,7 +7356,6 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
static void
parse_breakpoint_sals (char **address,
- struct symtabs_and_lines *sals,
struct linespec_result *canonical)
{
char *addr_start = *address;
@@ -7492,10 +7369,11 @@ parse_breakpoint_sals (char **address,
address. */
if (last_displayed_sal_is_valid ())
{
+ struct linespec_sals lsal;
struct symtab_and_line sal;
init_sal (&sal); /* Initialize to zeroes. */
- sals->sals = (struct symtab_and_line *)
+ lsal.sals.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
/* Set sal's pspace, pc, symtab, and line to the values
@@ -7510,8 +7388,11 @@ parse_breakpoint_sals (char **address,
instances with the same symtab and line. */
sal.explicit_pc = 1;
- sals->sals[0] = sal;
- sals->nelts = 1;
+ lsal.sals.sals[0] = sal;
+ lsal.sals.nelts = 1;
+ lsal.canonical = NULL;
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
else
error (_("No default breakpoint address now."));
@@ -7521,40 +7402,15 @@ parse_breakpoint_sals (char **address,
/* Force almost all breakpoints to be in terms of the
current_source_symtab (which is decode_line_1's default).
This should produce the results we want almost all of the
- time while leaving the last displayed codepoint pointers
- alone.
-
- ObjC: However, don't match an Objective-C method name which
- may have a '+' or '-' succeeded by a '[' */
-
- struct symtab_and_line cursal = get_current_source_symtab_and_line ();
-
- if (last_displayed_sal_is_valid ()
- && (!cursal.symtab
- || ((strchr ("+-", (*address)[0]) != NULL)
- && ((*address)[1] != '['))))
- *sals = decode_line_1 (address, 1,
- get_last_displayed_symtab (),
- get_last_displayed_line (),
- canonical);
+ time while leaving default_breakpoint_* alone. */
+ if (last_displayed_sal_is_valid ())
+ decode_line_full (address, 1,
+ get_last_displayed_symtab (),
+ get_last_displayed_line (),
+ canonical, NULL, NULL);
else
- *sals = decode_line_1 (address, 1, (struct symtab *) NULL, 0,
- canonical);
- }
- /* For any SAL that didn't have a canonical string, fill one in. */
- if (sals->nelts > 0 && canonical->canonical == NULL)
- canonical->canonical = xcalloc (sals->nelts, sizeof (char *));
- if (addr_start != (*address))
- {
- int i;
-
- for (i = 0; i < sals->nelts; i++)
- {
- /* Add the string if not present. */
- if (canonical->canonical[i] == NULL)
- canonical->canonical[i] = savestring (addr_start,
- (*address) - addr_start);
- }
+ decode_line_full (address, 1, (struct symtab *) NULL, 0,
+ canonical, NULL, NULL);
}
}
@@ -7589,15 +7445,22 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch,
for (i = 0; i < sals->nelts; i++)
{
+ struct gdbarch *sarch;
+
sal = &sals->sals[i];
- rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+ sarch = get_sal_arch (*sal);
+ /* We fall back to GDBARCH if there is no architecture
+ associated with SAL. */
+ if (sarch == NULL)
+ sarch = gdbarch;
+ rslt = gdbarch_fast_tracepoint_valid_at (sarch, sal->pc,
NULL, &msg);
old_chain = make_cleanup (xfree, msg);
if (!rslt)
error (_("May not have a fast tracepoint at 0x%s%s"),
- paddress (gdbarch, sal->pc), (msg ? msg : ""));
+ paddress (sarch, sal->pc), (msg ? msg : ""));
do_cleanups (old_chain);
}
@@ -7739,9 +7602,7 @@ create_breakpoint (struct gdbarch *gdbarch,
int from_tty, int enabled, int internal)
{
volatile struct gdb_exception e;
- struct symtabs_and_lines sals;
- struct symtab_and_line pending_sal;
- char *copy_arg;
+ char *copy_arg = NULL;
char *addr_start = arg;
struct linespec_result canonical;
struct cleanup *old_chain;
@@ -7753,26 +7614,26 @@ create_breakpoint (struct gdbarch *gdbarch,
gdb_assert (ops != NULL);
- sals.sals = NULL;
- sals.nelts = 0;
init_linespec_result (&canonical);
if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
{
int i;
+ struct linespec_sals lsal;
- sals = decode_static_tracepoint_spec (&arg);
+ lsal.sals = decode_static_tracepoint_spec (&arg);
copy_arg = savestring (addr_start, arg - addr_start);
- canonical.canonical = xcalloc (sals.nelts, sizeof (char *));
- for (i = 0; i < sals.nelts; i++)
- canonical.canonical[i] = xstrdup (copy_arg);
+
+ lsal.canonical = xstrdup (copy_arg);
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+
goto done;
}
TRY_CATCH (e, RETURN_MASK_ALL)
{
- parse_breakpoint_sals (&arg, &sals, &canonical);
+ parse_breakpoint_sals (&arg, &canonical);
}
/* If caller is interested in rc value from parse, set value. */
@@ -7804,35 +7665,31 @@ create_breakpoint (struct gdbarch *gdbarch,
a pending breakpoint and selected yes, or pending
breakpoint behavior is on and thus a pending breakpoint
is defaulted on behalf of the user. */
- copy_arg = xstrdup (addr_start);
- canonical.canonical = ©_arg;
- sals.nelts = 1;
- sals.sals = &pending_sal;
- pending_sal.pc = 0;
- pending = 1;
+ {
+ struct linespec_sals lsal;
+
+ copy_arg = xstrdup (addr_start);
+ lsal.canonical = xstrdup (copy_arg);
+ lsal.sals.nelts = 1;
+ lsal.sals.sals = XNEW (struct symtab_and_line);
+ init_sal (&lsal.sals.sals[0]);
+ pending = 1;
+ VEC_safe_push (linespec_sals, canonical.sals, &lsal);
+ }
break;
default:
throw_exception (e);
}
break;
default:
- if (!sals.nelts)
+ if (VEC_empty (linespec_sals, canonical.sals))
return 0;
}
done:
/* Create a chain of things that always need to be cleaned up. */
- old_chain = make_cleanup (null_cleanup, 0);
-
- if (!pending)
- {
- /* Make sure that all storage allocated to SALS gets freed. */
- make_cleanup (xfree, sals.sals);
-
- /* Cleanup the canonical array but not its contents. */
- make_cleanup (xfree, canonical.canonical);
- }
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
/* ----------------------------- SNIP -----------------------------
Anything added to the cleanup chain beyond this point is assumed
@@ -7840,28 +7697,36 @@ create_breakpoint (struct gdbarch *gdbarch,
then the memory is not reclaimed. */
bkpt_chain = make_cleanup (null_cleanup, 0);
- /* Mark the contents of the canonical for cleanup. These go on
- the bkpt_chain and only occur if the breakpoint create fails. */
- for (i = 0; i < sals.nelts; i++)
- {
- if (canonical.canonical[i] != NULL)
- make_cleanup (xfree, canonical.canonical[i]);
- }
-
/* Resolve all line numbers to PC's and verify that the addresses
are ok for the target. */
if (!pending)
- breakpoint_sals_to_pc (&sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ breakpoint_sals_to_pc (&iter->sals);
+ }
/* Fast tracepoints may have additional restrictions on location. */
if (!pending && type_wanted == bp_fast_tracepoint)
- check_fast_tracepoint_sals (gdbarch, &sals);
+ {
+ int ix;
+ struct linespec_sals *iter;
+
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ check_fast_tracepoint_sals (gdbarch, &iter->sals);
+ }
/* Verify that condition can be parsed, before setting any
breakpoints. Allocate a separate condition expression for each
breakpoint. */
if (!pending)
{
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+
if (parse_condition_and_thread)
{
/* Here we only parse 'arg' to separate condition
@@ -7870,7 +7735,7 @@ create_breakpoint (struct gdbarch *gdbarch,
re-parse it in context of each sal. */
cond_string = NULL;
thread = -1;
- find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+ find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string,
&thread, &task);
if (cond_string)
make_cleanup (xfree, cond_string);
@@ -7892,24 +7757,26 @@ create_breakpoint (struct gdbarch *gdbarch,
expand multiple locations for each sal, given than SALS
already should contain all sals for MARKER_ID. */
if (type_wanted == bp_static_tracepoint
- && is_marker_spec (canonical.canonical[0]))
+ && is_marker_spec (lsal->canonical))
{
int i;
- for (i = 0; i < sals.nelts; ++i)
+ for (i = 0; i < lsal->sals.nelts; ++i)
{
struct symtabs_and_lines expanded;
struct tracepoint *tp;
struct cleanup *old_chain;
+ char *addr_string;
expanded.nelts = 1;
- expanded.sals = xmalloc (sizeof (struct symtab_and_line));
- expanded.sals[0] = sals.sals[i];
- old_chain = make_cleanup (xfree, expanded.sals);
+ expanded.sals = &lsal->sals.sals[i];
+
+ addr_string = xstrdup (canonical.addr_string);
+ old_chain = make_cleanup (xfree, addr_string);
tp = XCNEW (struct tracepoint);
init_breakpoint_sal (&tp->base, gdbarch, expanded,
- canonical.canonical[i],
+ addr_string, NULL,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
@@ -7925,11 +7792,11 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, &tp->base, 0);
- do_cleanups (old_chain);
+ discard_cleanups (old_chain);
}
}
else
- create_breakpoints_sal (gdbarch, sals, &canonical, cond_string,
+ create_breakpoints_sal (gdbarch, &canonical, cond_string,
type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
@@ -7953,7 +7820,7 @@ create_breakpoint (struct gdbarch *gdbarch,
init_raw_breakpoint_without_location (b, gdbarch, type_wanted, ops);
- b->addr_string = canonical.canonical[0];
+ b->addr_string = copy_arg;
b->cond_string = NULL;
b->ignore_count = ignore_count;
b->disposition = tempflag ? disp_del : disp_donttouch;
@@ -7965,7 +7832,7 @@ create_breakpoint (struct gdbarch *gdbarch,
install_breakpoint (internal, b, 0);
}
- if (sals.nelts > 1)
+ if (VEC_length (linespec_sals, canonical.sals) > 1)
{
warning (_("Multiple breakpoints were set.\nUse the "
"\"delete\" command to delete unwanted breakpoints."));
@@ -8346,8 +8213,8 @@ break_range_command (char *arg, int from_tty)
CORE_ADDR end;
struct breakpoint *b;
struct symtab_and_line sal_start, sal_end;
- struct symtabs_and_lines sals_start, sals_end;
struct cleanup *cleanup_bkpt;
+ struct linespec_sals *lsal_start, *lsal_end;
/* We don't support software ranged breakpoints. */
if (target_ranged_break_num_registers () < 0)
@@ -8360,71 +8227,58 @@ break_range_command (char *arg, int from_tty)
if (can_use_bp < 0)
error (_("Hardware breakpoints used exceeds limit."));
+ arg = skip_spaces (arg);
if (arg == NULL || arg[0] == '\0')
error(_("No address range specified."));
- sals_start.sals = NULL;
- sals_start.nelts = 0;
init_linespec_result (&canonical_start);
- while (*arg == ' ' || *arg == '\t')
- arg++;
-
- parse_breakpoint_sals (&arg, &sals_start, &canonical_start);
+ parse_breakpoint_sals (&arg, &canonical_start);
- sal_start = sals_start.sals[0];
- addr_string_start = canonical_start.canonical[0];
- cleanup_bkpt = make_cleanup (xfree, addr_string_start);
- xfree (sals_start.sals);
- xfree (canonical_start.canonical);
+ cleanup_bkpt = make_cleanup_destroy_linespec_result (&canonical_start);
if (arg[0] != ',')
error (_("Too few arguments."));
- else if (sals_start.nelts == 0)
+ else if (VEC_empty (linespec_sals, canonical_start.sals))
error (_("Could not find location of the beginning of the range."));
- else if (sals_start.nelts != 1)
+
+ lsal_start = VEC_index (linespec_sals, canonical_start.sals, 0);
+
+ if (VEC_length (linespec_sals, canonical_start.sals) > 1
+ || lsal_start->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_start);
+ sal_start = lsal_start->sals.sals[0];
+ addr_string_start = lsal_start->canonical;
arg++; /* Skip the comma. */
- while (*arg == ' ' || *arg == '\t')
- arg++;
+ arg = skip_spaces (arg);
/* Parse the end location. */
- sals_end.sals = NULL;
- sals_end.nelts = 0;
init_linespec_result (&canonical_end);
arg_start = arg;
- /* We call decode_line_1 directly here instead of using
+ /* We call decode_line_full directly here instead of using
parse_breakpoint_sals because we need to specify the start location's
symtab and line as the default symtab and line for the end of the
range. This makes it possible to have ranges like "foo.c:27, +14",
where +14 means 14 lines from the start location. */
- sals_end = decode_line_1 (&arg, 1, sal_start.symtab, sal_start.line,
- &canonical_end);
-
- /* canonical_end can be NULL if it was of the form "*0xdeadbeef". */
- if (canonical_end.canonical == NULL)
- canonical_end.canonical = xcalloc (1, sizeof (char *));
- /* Add the string if not present. */
- if (arg_start != arg && canonical_end.canonical[0] == NULL)
- canonical_end.canonical[0] = savestring (arg_start, arg - arg_start);
-
- sal_end = sals_end.sals[0];
- addr_string_end = canonical_end.canonical[0];
- make_cleanup (xfree, addr_string_end);
- xfree (sals_end.sals);
- xfree (canonical_end.canonical);
-
- if (sals_end.nelts == 0)
+ decode_line_full (&arg, 1, sal_start.symtab, sal_start.line,
+ &canonical_end, NULL, NULL);
+
+ make_cleanup_destroy_linespec_result (&canonical_end);
+
+ if (VEC_empty (linespec_sals, canonical_end.sals))
error (_("Could not find location of the end of the range."));
- else if (sals_end.nelts != 1)
+
+ lsal_end = VEC_index (linespec_sals, canonical_end.sals, 0);
+ if (VEC_length (linespec_sals, canonical_end.sals) > 1
+ || lsal_end->sals.nelts != 1)
error (_("Cannot create a ranged breakpoint with multiple locations."));
- resolve_sal_pc (&sal_end);
+ sal_end = lsal_end->sals.sals[0];
+ addr_string_end = lsal_end->canonical;
end = find_breakpoint_range_end (sal_end);
if (sal_start.pc > end)
@@ -8451,11 +8305,11 @@ break_range_command (char *arg, int from_tty)
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
b->disposition = disp_donttouch;
- b->addr_string = addr_string_start;
- b->addr_string_range_end = addr_string_end;
+ b->addr_string = xstrdup (addr_string_start);
+ b->addr_string_range_end = xstrdup (addr_string_end);
b->loc->length = length;
- discard_cleanups (cleanup_bkpt);
+ do_cleanups (cleanup_bkpt);
mention (b);
observer_notify_breakpoint_created (b);
@@ -9564,10 +9418,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&arg, 1,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
- sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+ sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0);
if (sals.nelts != 1)
error (_("Couldn't get information on specified line."));
@@ -10150,18 +10003,21 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
- && (loc->pspace == sal.pspace)
- && (loc->address == sal.pc)
- && (!section_is_overlay (loc->section)
- || loc->section == sal.section);
- int line_match = ((default_match || (0 == sal.pc))
- && b->source_file != NULL
+ /* If the user specified file:line, don't allow a PC
+ match. This matches historical gdb behavior. */
+ int pc_match = (!sal.explicit_line
+ && sal.pc
+ && (loc->pspace == sal.pspace)
+ && (loc->address == sal.pc)
+ && (!section_is_overlay (loc->section)
+ || loc->section == sal.section));
+ int line_match = ((default_match || sal.explicit_line)
+ && loc->source_file != NULL
&& sal.symtab != NULL
&& sal.pspace == loc->pspace
- && filename_cmp (b->source_file,
+ && filename_cmp (loc->source_file,
sal.symtab->filename) == 0
- && b->line_number == sal.line);
+ && loc->line_number == sal.line);
if (pc_match || line_match)
{
match = 1;
@@ -10753,15 +10609,25 @@ say_where (struct breakpoint *b)
}
else
{
- if (opts.addressprint || b->source_file == NULL)
+ if (opts.addressprint || b->loc->source_file == NULL)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
gdb_stdout);
}
- if (b->source_file)
- printf_filtered (": file %s, line %d.",
- b->source_file, b->line_number);
+ if (b->loc->source_file)
+ {
+ /* If there is a single location, we can print the location
+ more nicely. */
+ if (b->loc->next == NULL)
+ printf_filtered (": file %s, line %d.",
+ b->loc->source_file, b->loc->line_number);
+ else
+ /* This is not ideal, but each location may have a
+ different file name, and this at least reflects the
+ real situation somewhat. */
+ printf_filtered (": %s.", b->addr_string);
+ }
if (b->loc->next)
{
@@ -10781,6 +10647,7 @@ bp_location_dtor (struct bp_location *self)
{
xfree (self->cond);
xfree (self->function_name);
+ xfree (self->source_file);
}
static const struct bp_location_ops bp_location_ops =
@@ -10797,8 +10664,8 @@ base_breakpoint_dtor (struct breakpoint *self)
decref_counted_command_line (&self->commands);
xfree (self->cond_string);
xfree (self->addr_string);
+ xfree (self->filter);
xfree (self->addr_string_range_end);
- xfree (self->source_file);
}
static struct bp_location *
@@ -11629,17 +11496,18 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
ui_out_field_int (uiout, "line", sal.line);
ui_out_text (uiout, "\n");
- b->line_number = sal.line;
+ b->loc->line_number = sal.line;
- xfree (b->source_file);
+ xfree (b->loc->source_file);
if (sym)
- b->source_file = xstrdup (sal.symtab->filename);
+ b->loc->source_file = xstrdup (sal.symtab->filename);
else
- b->source_file = NULL;
+ b->loc->source_file = NULL;
xfree (b->addr_string);
b->addr_string = xstrprintf ("%s:%d",
- sal.symtab->filename, b->line_number);
+ sal.symtab->filename,
+ b->loc->line_number);
/* Might be nice to check if function changed, and warn if
so. */
@@ -11689,8 +11557,17 @@ update_breakpoint_locations (struct breakpoint *b,
int i;
struct bp_location *existing_locations = b->loc;
- /* Ranged breakpoints have only one start location and one end location. */
- gdb_assert (sals_end.nelts == 0 || (sals.nelts == 1 && sals_end.nelts == 1));
+ if (sals_end.nelts != 0 && (sals.nelts != 1 || sals_end.nelts != 1))
+ {
+ /* Ranged breakpoints have only one start location and one end
+ location. */
+ b->enable_state = bp_disabled;
+ update_global_location_list (1);
+ printf_unfiltered (_("Could not reset ranged breakpoint %d: "
+ "multiple locations found\n"),
+ b->number);
+ return;
+ }
/* If there's no new locations, and all existing locations are
pending, don't do anything. This optimizes the common case where
@@ -11705,8 +11582,11 @@ update_breakpoint_locations (struct breakpoint *b,
for (i = 0; i < sals.nelts; ++i)
{
- struct bp_location *new_loc =
- add_location_to_breakpoint (b, &(sals.sals[i]));
+ struct bp_location *new_loc;
+
+ switch_to_program_space_and_thread (sals.sals[i].pspace);
+
+ new_loc = add_location_to_breakpoint (b, &(sals.sals[i]));
/* Reparse conditions, they might contain references to the
old symtab. */
@@ -11730,16 +11610,6 @@ update_breakpoint_locations (struct breakpoint *b,
}
}
- if (b->source_file != NULL)
- xfree (b->source_file);
- if (sals.sals[i].symtab == NULL)
- b->source_file = NULL;
- else
- b->source_file = xstrdup (sals.sals[i].symtab->filename);
-
- if (b->line_number == 0)
- b->line_number = sals.sals[i].line;
-
if (sals_end.nelts)
{
CORE_ADDR end = find_breakpoint_range_end (sals_end.sals[0]);
@@ -11806,7 +11676,7 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
char *s;
int marker_spec;
struct symtabs_and_lines sals = {0};
- struct gdb_exception e;
+ volatile struct gdb_exception e;
s = addr_string;
marker_spec = b->type == bp_static_tracepoint && is_marker_spec (s);
@@ -11827,7 +11697,30 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
error (_("marker %s not found"), tp->static_trace_marker_id);
}
else
- sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
+ {
+ struct linespec_result canonical;
+
+ init_linespec_result (&canonical);
+ decode_line_full (&s, 1, (struct symtab *) NULL, 0,
+ &canonical, multiple_symbols_all,
+ b->filter);
+
+ /* We should get 0 or 1 resulting SALs. */
+ gdb_assert (VEC_length (linespec_sals, canonical.sals) < 2);
+
+ if (VEC_length (linespec_sals, canonical.sals) > 0)
+ {
+ struct linespec_sals *lsal;
+
+ lsal = VEC_index (linespec_sals, canonical.sals, 0);
+ sals = lsal->sals;
+ /* Arrange it so the destructor does not free the
+ contents. */
+ lsal->sals.sals = NULL;
+ }
+
+ destroy_linespec_result (&canonical);
+ }
}
if (e.reason < 0)
{
@@ -11861,9 +11754,10 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
if (e.reason == 0 || e.error != NOT_FOUND_ERROR)
{
- gdb_assert (sals.nelts == 1);
+ int i;
- resolve_sal_pc (&sals.sals[0]);
+ for (i = 0; i < sals.nelts; ++i)
+ resolve_sal_pc (&sals.sals[i]);
if (b->condition_not_parsed && s && s[0])
{
char *cond_string = 0;
@@ -11906,7 +11800,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals.sals);
- expanded = expand_line_sal_maybe (sals.sals[0]);
+ expanded = sals;
}
if (b->addr_string_range_end)
@@ -11915,7 +11809,7 @@ breakpoint_re_set_default (struct breakpoint *b)
if (found)
{
make_cleanup (xfree, sals_end.sals);
- expanded_end = expand_line_sal_maybe (sals_end.sals[0]);
+ expanded_end = sals_end;
}
}
@@ -12453,11 +12347,10 @@ decode_line_spec_1 (char *string, int funfirstline)
if (last_displayed_sal_is_valid ())
sals = decode_line_1 (&string, funfirstline,
get_last_displayed_symtab (),
- get_last_displayed_line (),
- NULL);
+ get_last_displayed_line ());
else
sals = decode_line_1 (&string, funfirstline,
- (struct symtab *) NULL, 0, NULL);
+ (struct symtab *) NULL, 0);
if (*string)
error (_("Junk at end of line specification: %s"), string);
return sals;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7b04bf7..65527ae 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -397,6 +397,14 @@ struct bp_location
This variable keeps a number of events still to go, when
it becomes 0 this location is retired. */
int events_till_retirement;
+
+ /* Line number of this address. */
+
+ int line_number;
+
+ /* Source file name of this address. */
+
+ char *source_file;
};
/* This structure is a collection of function pointers that, if available,
@@ -544,14 +552,6 @@ struct breakpoint
/* Location(s) associated with this high-level breakpoint. */
struct bp_location *loc;
- /* Line number of this address. */
-
- int line_number;
-
- /* Source file name of this address. */
-
- char *source_file;
-
/* Non-zero means a silent breakpoint (don't print frame info
if we stop here). */
unsigned char silent;
@@ -575,6 +575,11 @@ struct breakpoint
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
+ /* The filter that should be passed to decode_line_full when
+ re-setting this breakpoint. This may be NULL, but otherwise is
+ allocated with xmalloc. */
+ char *filter;
+
/* For a ranged breakpoint, the string we used to find
the end of the range (malloc'd). */
char *addr_string_range_end;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index d75a6c0..25e60e1 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -92,6 +92,9 @@ void apropos_command (char *, int);
/* Prototypes for local utility functions */
static void ambiguous_line_spec (struct symtabs_and_lines *);
+
+static void filter_sals (struct symtabs_and_lines *);
+
\f
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
@@ -246,16 +249,6 @@ help_command (char *command, int from_tty)
help_cmd (command, gdb_stdout);
}
\f
-/* String compare function for qsort. */
-static int
-compare_strings (const void *arg1, const void *arg2)
-{
- const char **s1 = (const char **) arg1;
- const char **s2 = (const char **) arg2;
-
- return strcmp (*s1, *s2);
-}
-
/* The "complete" command is used by Emacs to implement completion. */
static void
@@ -796,8 +789,9 @@ edit_command (char *arg, int from_tty)
/* Now should only be one argument -- decode it in SAL. */
arg1 = arg;
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (! sals.nelts)
{
/* C++ */
@@ -926,8 +920,9 @@ list_command (char *arg, int from_tty)
dummy_beg = 1;
else
{
- sals = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals = decode_line_list (&arg1, 0, 0, 0);
+ filter_sals (&sals);
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
@@ -959,9 +954,10 @@ list_command (char *arg, int from_tty)
else
{
if (dummy_beg)
- sals_end = decode_line_1 (&arg1, 0, 0, 0, 0);
+ sals_end = decode_line_list (&arg1, 0, 0, 0);
else
- sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0);
+ sals_end = decode_line_list (&arg1, 0, sal.symtab, sal.line);
+ filter_sals (&sals);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
@@ -1472,6 +1468,85 @@ ambiguous_line_spec (struct symtabs_and_lines *sals)
sals->sals[i].symtab->filename, sals->sals[i].line);
}
+/* Sort function for filter_sals. */
+
+static int
+compare_symtabs (const void *a, const void *b)
+{
+ const struct symtab_and_line *sala = a;
+ const struct symtab_and_line *salb = b;
+ int r;
+
+ if (!sala->symtab->dirname)
+ {
+ if (salb->symtab->dirname)
+ return -1;
+ }
+ else if (!salb->symtab->dirname)
+ {
+ if (sala->symtab->dirname)
+ return 1;
+ }
+ else
+ {
+ r = filename_cmp (sala->symtab->dirname, salb->symtab->dirname);
+ if (r)
+ return r;
+ }
+
+ r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+ if (r)
+ return r;
+
+ if (sala->line < salb->line)
+ return -1;
+ return sala->line == salb->line ? 0 : 1;
+}
+
+/* Remove any SALs that do not match the current program space, or
+ which appear to be "file:line" duplicates. */
+
+static void
+filter_sals (struct symtabs_and_lines *sals)
+{
+ int i, out, prev;
+
+ out = 0;
+ for (i = 0; i < sals->nelts; ++i)
+ {
+ if (sals->sals[i].pspace == current_program_space
+ || sals->sals[i].symtab == NULL)
+ {
+ sals->sals[out] = sals->sals[i];
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
+ compare_symtabs);
+
+ out = 1;
+ prev = 0;
+ for (i = 1; i < sals->nelts; ++i)
+ {
+ if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
+ {
+ /* Symtabs differ. */
+ sals->sals[out] = sals->sals[i];
+ prev = out;
+ ++out;
+ }
+ }
+ sals->nelts = out;
+
+ if (sals->nelts == 0)
+ {
+ xfree (sals->sals);
+ sals->sals = NULL;
+ }
+}
+
static void
set_debug (char *arg, int from_tty)
{
diff --git a/gdb/defs.h b/gdb/defs.h
index b5bc6c5..040d9c9 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -425,6 +425,7 @@ char *ldirname (const char *filename);
char **gdb_buildargv (const char *);
int compare_positive_ints (const void *ap, const void *bp);
+int compare_strings (const void *ap, const void *bp);
/* A wrapper for bfd_errmsg to produce a more helpful error message
in the case of bfd_error_file_ambiguously recognized.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8a7d7e9..7547a40 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -443,9 +443,6 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr)
return sym;
}
-/* Define VEC (CORE_ADDR) functions. */
-DEF_VEC_I (CORE_ADDR);
-
/* Verify function with entry point exact address ADDR can never call itself
via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it
can call itself via tail calls.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 5e279de..de1aac3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -2439,10 +2439,38 @@ dw2_forget_cached_source_info (struct objfile *objfile)
dw2_free_cached_file_names, NULL);
}
+/* Helper function for dw2_map_symtabs_matching_filename that expands
+ the symtabs and calls the iterator. */
+
+static int
+dw2_map_expand_apply (struct objfile *objfile,
+ struct dwarf2_per_cu_data *per_cu,
+ const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded CUs. */
+ if (per_cu->v.quick->symtab)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ dw2_instantiate_symtab (objfile, per_cu);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
static int
-dw2_lookup_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
+dw2_map_symtabs_matching_filename (struct objfile *objfile, const char *name,
+ const char *full_path, const char *real_path,
+ int (*callback) (struct symtab *, void *),
+ void *data)
{
int i;
const char *name_basename = lbasename (name);
@@ -2471,8 +2499,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (FILENAME_CMP (name, this_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
if (check_basename && ! base_cu
@@ -2493,8 +2523,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (full_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
@@ -2506,8 +2538,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (this_real_name != NULL
&& FILENAME_CMP (real_path, this_real_name) == 0)
{
- *result = dw2_instantiate_symtab (objfile, per_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, per_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
}
}
@@ -2515,8 +2549,10 @@ dw2_lookup_symtab (struct objfile *objfile, const char *name,
if (base_cu)
{
- *result = dw2_instantiate_symtab (objfile, base_cu);
- return 1;
+ if (dw2_map_expand_apply (objfile, base_cu,
+ name, full_path, real_path,
+ callback, data))
+ return 1;
}
return 0;
@@ -2862,7 +2898,7 @@ const struct quick_symbol_functions dwarf2_gdb_index_functions =
dw2_has_symbols,
dw2_find_last_source_symtab,
dw2_forget_cached_source_info,
- dw2_lookup_symtab,
+ dw2_map_symtabs_matching_filename,
dw2_lookup_symbol,
dw2_pre_expand_symtabs_matching,
dw2_print_stats,
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 64ba837..3e06f09 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -45,108 +45,246 @@
#include "cli/cli-utils.h"
#include "filenames.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_variable (struct linespec_state *self,
+ char *copy);
-static struct symtabs_and_lines decode_line_2 (struct symbol *[],
- int, int,
- struct linespec_result *);
+static int symbol_to_sal (struct symtab_and_line *result,
+ int funfirstline, struct symbol *sym);
-static struct symtab *symtab_from_filename (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 symbol *find_function_symbol (char **argptr, char *p,
- int is_quote_enclosed);
+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_all_digits (char **argptr,
- struct symtab *default_symtab,
- int default_line,
- struct linespec_result *canonical,
- struct symtab *file_symtab,
- char *q);
+/* Helper functions. */
-static struct symtabs_and_lines decode_dollar (char *copy,
- int funfirstline,
- struct symtab *default_symtab,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* Add SAL to SALS. */
-static int decode_label (struct symbol *function_symbol,
- char *copy, struct linespec_result *canonical,
- struct symtabs_and_lines *result);
+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 decode_variable (char *copy,
- int funfirstline,
- struct linespec_result *canonical,
- struct symtab *file_symtab);
+/* 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 symbol_found (int funfirstline,
- struct linespec_result *canonical,
- char *copy,
- struct symbol *sym,
- struct symtab *file_symtab,
- struct symbol *function_symbol);
+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);
-static struct
-symtabs_and_lines minsym_found (int funfirstline,
- struct minimal_symbol *msymbol);
+ if (self->canonical)
+ {
+ char *canonical_name = NULL;
-/* Helper functions. */
+ self->canonical_names = xrealloc (self->canonical_names,
+ sals->nelts * sizeof (char *));
+ if (sal->symtab && sal->symtab->filename)
+ {
+ char *filename = sal->symtab->filename;
+
+ /* FIXME: this is where we should do "FILE:FUNCTION:LINE",
+ to let us distinguish between different template
+ instantiations. */
+ 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 +319,64 @@ 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 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 (strcmp_iw (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;
+
+ ALL_PSPACES (pspace)
+ {
+ if (search_pspace != NULL && search_pspace != pspace)
+ continue;
+ if (pspace->executing_startup)
+ continue;
- for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
- count += total_number_of_methods (TYPE_BASECLASS (type, n));
+ set_current_program_space (pspace);
- return count;
+ ALL_OBJFILES (objfile)
+ {
+ struct symtab *symtab;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
+ iterate_name_matcher,
+ ALL_DOMAIN,
+ &name);
+
+ ALL_OBJFILE_SYMTABS (objfile, symtab)
+ {
+ if (symtab->primary)
+ {
+ struct block *block;
+ block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ iterate_over_symbols (block, name, domain, callback, data);
+ }
+ }
+ }
+ }
}
/* Returns the block to be used for symbol searches for the given SYMTAB,
@@ -227,40 +403,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 +448,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;
-}
-
-/* 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;
+ for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+ VEC_safe_push (typep, *superclasses, TYPE_BASECLASS (t, ibase));
}
-
-
/* 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 +529,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 +684,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 +827,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 +847,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 +893,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 +926,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 +959,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 +981,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 +1005,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 +1031,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,91 +1079,238 @@ 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;
+ }
}
-\f
+/* A constructor for linespec_state. */
-/* 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. */
+static void
+linespec_state_constructor (struct linespec_state *self,
+ int funfirstline,
+ struct symtab *default_symtab,
+ int default_line,
+ struct linespec_result *canonical)
+{
+ memset (self, 0, sizeof (*self));
+ self->funfirstline = funfirstline;
+ 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);
+}
-/* First, some functions to initialize stuff at the beggining of the
- function. */
+/* A destructor for linespec_state. */
static void
-initialize_defaults (struct symtab **default_symtab, int *default_line)
+linespec_state_destructor (void *arg)
{
- if (*default_symtab == 0)
- {
- /* Use whatever we have for the default source line. We don't use
- get_current_or_default_symtab_and_line as it can recurse and call
- us back! */
- struct symtab_and_line cursal =
- get_current_source_symtab_and_line ();
-
- *default_symtab = cursal.symtab;
- *default_line = cursal.line;
- }
-}
+ struct linespec_state *self = arg;
-\f
+ xfree (self->user_filename);
+ xfree (self->user_function);
+ VEC_free (symtab_p, self->file_symtabs);
+ htab_delete (self->addr_set);
+}
-/* Decode arg of the form *PC. */
+/* See linespec.h. */
-static struct symtabs_and_lines
-decode_indirect (char **argptr)
+void
+decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter)
{
- struct symtabs_and_lines values;
- CORE_ADDR pc;
+ 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);
+
+ linespec_state_constructor (&state, funfirstline, 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;
+
+ 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 funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, 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;
+}
+
+/* See linespec.h. */
+
+struct symtabs_and_lines
+decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab,
+ int default_line)
+{
+ struct symtabs_and_lines result;
+ struct linespec_state state;
+ struct cleanup *cleanups;
+
+ linespec_state_constructor (&state, funfirstline, default_symtab,
+ default_line, NULL);
+ state.list_mode = 1;
+ cleanups = make_cleanup (linespec_state_destructor, &state);
+ save_current_program_space ();
+
+ result = decode_line_internal (&state, argptr);
+ do_cleanups (cleanups);
+ return result;
+}
+
+\f
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
+ }
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+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 +1323,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 +1433,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 +1461,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,
- ¤t_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,9 +1515,8 @@ 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;
@@ -1381,10 +1524,9 @@ decode_compound (char **argptr, int funfirstline,
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 +1561,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 +1661,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 +1718,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,8 +1728,10 @@ 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. */
@@ -1611,7 +1751,6 @@ decode_compound (char **argptr, int funfirstline,
/* Look up entire name. */
name = copy;
- cleanup = make_cleanup (null_cleanup, NULL);
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
@@ -1619,213 +1758,400 @@ decode_compound (char **argptr, int funfirstline,
make_cleanup (xfree, name);
}
- 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;
+ return decode_variable (self, copy);
+}
- /* 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);
- }
+/* An instance of this type is used when collecting prefix symbols for
+ decode_compound. */
- /* 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);
-}
+struct decode_compound_collector
+{
+ /* The result vector. */
+ VEC (symbolp) *symbols;
+
+ /* A hash table of all symbols we found. We use this to avoid
+ adding any symbol more than once. */
+ htab_t unique_syms;
+};
+
+/* A callback for iterate_over_symbols that is used by
+ lookup_prefix_sym to collect type symbols. */
+
+static int
+collect_one_symbol (struct symbol *sym, void *d)
+{
+ struct decode_compound_collector *collector = d;
+ void **slot;
+ struct type *t;
+
+ 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);
+ iterate_over_symbols (search_block, copy, STRUCT_DOMAIN,
+ collect_one_symbol, &collector);
+ 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;
+
+ 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;
- /* Find all methods with a matching name, and put them in
- sym_arr. */
+ 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);
+}
+
+\f
+
+/* 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;
}
-\f
+/* 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);
+ }
+
+ do_cleanups (cleanups);
+ return collector.symtabs;
+}
-/* Return the symtab associated to the filename given by the substring
- of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+/* Return all the symtabs associated to the filename 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 +2160,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 +2173,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);
+
+ 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 file_symtab;
+ 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,18 +2222,40 @@ 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 looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (VEC_empty (symbolp, result)
+ && current_language->la_language == language_ada)
+ {
+ struct symbol *function_symbol;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (function_symbol && SYMBOL_CLASS (function_symbol) == LOC_BLOCK)
+ {
+ xfree (copy);
+ copy = xstrdup (SYMBOL_SEARCH_NAME (function_symbol));
+ *user_function = copy;
+ iterate_over_all_matching_symtabs (copy, VAR_DOMAIN,
+ collect_function_symbols,
+ &result, NULL);
+ }
+ }
+
+ if (VEC_empty (symbolp, result))
+ VEC_free (symbolp, result);
+ else
+ {
+ /* Discard the file name from the arg. */
+ *argptr = skip_spaces (p1 + 1);
+ }
- return function_symbol;
+ return result;
}
\f
@@ -1901,13 +2265,16 @@ find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
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 ix;
+ struct symtab *elt;
+ int use_default = 0;
+ char *saved_arg = *argptr;
enum sign
{
@@ -1915,12 +2282,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 +2292,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 +2317,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 +2332,84 @@ 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);
+
+ 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));
+
+ if (self->list_mode)
+ {
+ /* 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);
+ }
+ else
+ {
+ int pcix;
+ CORE_ADDR pc;
+ VEC (CORE_ADDR) *pcs;
+
+ pcs = find_pcs_for_symtab_line (elt, val.line);
+ if (VEC_empty (CORE_ADDR, pcs))
+ continue;
+
+ for (pcix = 0; VEC_iterate (CORE_ADDR, pcs, pcix, pc); ++pcix)
+ {
+ struct block *block;
+ struct symbol *sym;
+
+ val.symtab = elt;
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = pc;
+ val.explicit_line = 1;
+
+ block = block_for_pc (val.pc);
+ sym = block ? block_containing_function (block) : NULL;
+
+ skip_prologue_sal (&val);
+
+ add_sal_to_sals (self, &values, &val,
+ sym ? SYMBOL_NATURAL_NAME (sym) : NULL);
+ }
+
+ VEC_free (CORE_ADDR, pcs);
+ }
+ }
+
+ 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 +2418,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 +2450,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 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.reason == 0)
+ return values;
+
+ 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 +2471,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;
+
+ add_sal_to_sals (self, &values, &val, NULL);
+ }
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ 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 +2510,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 +2519,308 @@ 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;
+ }
+
+ 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)
+ {
+ 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;
+
+ 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, ¤t_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. */
- sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+static void
+add_matching_symbols_to_info (const char *name,
+ struct collect_info *info,
+ struct program_space *pspace)
+{
+ int ix;
+ struct symtab *elt;
- if (sym != NULL)
- *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+ for (ix = 0; VEC_iterate (symtab_p, info->state->file_symtabs, ix, elt); ++ix)
+ {
+ struct symbol *sym;
- return sym != NULL;
+ 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));
+ 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);
+ 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);
+
canon = cp_canonicalize_string_no_typedefs (copy);
if (canon != NULL)
{
- name = canon;
- make_cleanup (xfree, name);
+ make_cleanup (xfree, canon);
+ lookup_name = canon;
}
- sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+ add_matching_symbols_to_info (lookup_name, &info, NULL);
- if (sym != NULL)
+ /* If looking up the given name failed, try using the current
+ language to look up a symbol. This may augment the search. If a
+ symbol is found this way, repeat the iteration, but using the
+ discovered name. */
+ if (info.result.nelts == 0 && current_language->la_language == language_ada)
{
- do_cleanups (cleanup);
- return symbol_found (funfirstline, canonical, copy, sym,
- file_symtab, NULL);
- }
+ struct symbol *sym;
- msymbol = lookup_minimal_symbol (name, NULL, NULL);
- do_cleanups (cleanup);
+ sym = lookup_symbol (lookup_name, get_selected_block (0), VAR_DOMAIN, 0);
+ if (sym)
+ {
+ copy = SYMBOL_SEARCH_NAME (sym);
+ add_matching_symbols_to_info (copy, &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 +2829,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,
- ¤t_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;
- if (funfirstline)
- skip_prologue_sal (&values.sals[0]);
+ 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);
+}
- values.nelts = 1;
- return values;
+/* Cleanup function for a linespec_result. */
+
+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);
}
diff --git a/gdb/linespec.h b/gdb/linespec.h
index 3c86af3..d32f401 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -20,8 +20,30 @@
struct symtab;
+#include "vec.h"
+
+/* decode_line_full returns a vector of these. */
+
+struct linespec_sals
+{
+ /* This is the linespec corresponding to the sals contained in this
+ object. It can be passed as the FILTER argument to future calls
+ to decode_line_full. This is freed by
+ destroy_linespec_result. */
+ char *canonical;
+
+ /* Sals. The 'sals' field is destroyed by
+ destroy_linespec_result. */
+ struct symtabs_and_lines sals;
+};
+
+typedef struct linespec_sals linespec_sals;
+DEF_VEC_O (linespec_sals);
+
/* An instance of this may be filled in by decode_line_1. The caller
- must call init_linespec_result to initialize it. */
+ must call init_linespec_result to initialize it and
+ destroy_linespec_result to destroy it. The caller must make copies
+ of any data that it needs to keep. */
struct linespec_result
{
@@ -30,22 +52,85 @@ struct linespec_result
display mechanism would do the wrong thing. */
int special_display;
- /* If non-NULL, an array of canonical names for returned
- symtab_and_line objects. The array has as many elements as the
- `nelts' field in the symtabs_and_line returned by decode_line_1.
- An element in the array may be NULL. The array and each non-NULL
- element in it are allocated with xmalloc and must be freed by the
- caller. */
- char **canonical;
+ /* If non-zero, the linespec result should be considered to be a
+ "pre-expanded" multi-location linespec. A pre-expanded linespec
+ holds all matching locations in a single linespec_sals
+ object. */
+ int pre_expanded;
+
+ /* If PRE_EXPANDED is non-zero, this is set to the linespec entered
+ by the user. This will be freed by destroy_linespec_result. */
+ char *addr_string;
+
+ /* The sals. The vector will be freed by
+ destroy_linespec_result. */
+ VEC (linespec_sals) *sals;
};
/* Initialize a linespec_result. */
extern void init_linespec_result (struct linespec_result *);
+/* Destroy a linespec_result. */
+
+extern void destroy_linespec_result (struct linespec_result *);
+
+/* Return a cleanup that destroys a linespec_result. */
+
+extern struct cleanup *
+ make_cleanup_destroy_linespec_result (struct linespec_result *);
+
extern struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline,
- struct symtab *default_symtab, int default_line,
- struct linespec_result *canonical);
+ struct symtab *default_symtab, int default_line);
+
+/* Like decode_line_1, but useful only for the 'list' command. With
+ this variant, a "file:line" linespec will always return a result. */
+
+extern struct symtabs_and_lines
+ decode_line_list (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line);
+
+/* Parse *ARGPTR as a linespec and return results. This is the "full"
+ interface to this module, which handles multiple results
+ properly.
+
+ FUNFIRSTLINE is nonzero if we want the resulting SALs to describe
+ the first line of indicated functions.
+
+ DEFAULT_SYMTAB and DEFAULT_LINE describe the default location.
+ DEFAULT_SYMTAB can be NULL, in which case the current symtab and
+ line are used.
+
+ CANONICAL is where the results are stored. It must not be NULL.
+
+ SELECT_MODE must be one of the multiple_symbols_* constants, or
+ NULL. It determines how multiple results will be handled. If
+ NULL, the appropriate CLI value will be used.
+
+ FILTER can either be NULL or a string holding a canonical name.
+ This is only valid when SELECT_MODE is multiple_symbols_all.
+
+ Multiple results are handled differently depending on the
+ arguments:
+
+ . With multiple_symbols_cancel, an exception is thrown.
+
+ . With multiple_symbols_ask, a menu is presented to the user. The
+ user may select none, in which case an exception is thrown; or all,
+ which is handled like multiple_symbols_all, below. Otherwise,
+ CANONICAL->SALS will have one entry for each name the user chose.
+
+ . With multiple_symbols_all, CANONICAL->SALS will have a single
+ entry describing all the matching locations. If FILTER is
+ non-NULL, then only locations whose canonical name is equal (in the
+ strcmp sense) to FILTER will be returned; all others will be
+ filtered out. */
+
+extern void decode_line_full (char **argptr, int funfirstline,
+ struct symtab *default_symtab, int default_line,
+ struct linespec_result *canonical,
+ const char *select_mode,
+ const char *filter);
#endif /* defined (LINESPEC_H) */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 70871cd..f90f036 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -310,6 +310,46 @@ lookup_minimal_symbol (const char *name, const char *sfile,
return NULL;
}
+/* Iterate over all the minimal symbols in the objfile OBJF which
+ match NAME. Both the ordinary and demangled names of each symbol
+ are considered. The caller is responsible for canonicalizing NAME,
+ should that need to be done.
+
+ For each matching symbol, CALLBACK is called with the symbol and
+ USER_DATA as arguments. */
+
+void
+iterate_over_minimal_symbols (struct objfile *objf, const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data)
+{
+ unsigned int hash;
+ struct minimal_symbol *iter;
+ int (*cmp) (const char *, const char *);
+
+ /* The first pass is over the ordinary hash table. */
+ hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_hash[hash];
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
+ while (iter)
+ {
+ if (cmp (SYMBOL_LINKAGE_NAME (iter), name) == 0)
+ (*callback) (iter, user_data);
+ iter = iter->hash_next;
+ }
+
+ /* The second pass is over the demangled table. */
+ hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
+ iter = objf->msymbol_demangled_hash[hash];
+ while (iter)
+ {
+ if (SYMBOL_MATCHES_SEARCH_NAME (iter, name))
+ (*callback) (iter, user_data);
+ iter = iter->demangled_hash_next;
+ }
+}
+
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a pointer
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 592b52e..dcf9459 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -952,49 +952,7 @@ classes_info (char *regexp, int from_tty)
printf_filtered (_("No classes matching \"%s\"\n"), regexp ? regexp : "*");
}
-/*
- * Function: find_imps (char *selector, struct symbol **sym_arr)
- *
- * Input: a string representing a selector
- * a pointer to an array of symbol pointers
- * possibly a pointer to a symbol found by the caller.
- *
- * Output: number of methods that implement that selector. Side
- * effects: The array of symbol pointers is filled with matching syms.
- *
- * By analogy with function "find_methods" (symtab.c), builds a list
- * of symbols matching the ambiguous input, so that "decode_line_2"
- * (symtab.c) can list them and ask the user to choose one or more.
- * In this case the matches are objective c methods
- * ("implementations") matching an objective c selector.
- *
- * Note that it is possible for a normal (c-style) function to have
- * the same name as an objective c selector. To prevent the selector
- * from eclipsing the function, we allow the caller (decode_line_1) to
- * search for such a function first, and if it finds one, pass it in
- * to us. We will then integrate it into the list. We also search
- * for one here, among the minsyms.
- *
- * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
- * into two parts: debuggable (struct symbol) syms, and
- * non_debuggable (struct minimal_symbol) syms. The debuggable
- * ones will come first, before NUM_DEBUGGABLE (which will thus
- * be the index of the first non-debuggable one).
- */
-
-/*
- * Function: total_number_of_imps (char *selector);
- *
- * Input: a string representing a selector
- * Output: number of methods that implement that selector.
- *
- * By analogy with function "total_number_of_methods", this allows
- * decode_line_1 (symtab.c) to detect if there are objective c methods
- * matching the input, and to allocate an array of pointers to them
- * which can be manipulated by "decode_line_2" (also in symtab.c).
- */
-
-char *
+static char *
parse_selector (char *method, char **selector)
{
char *s1 = NULL;
@@ -1050,7 +1008,7 @@ parse_selector (char *method, char **selector)
return s2;
}
-char *
+static char *
parse_method (char *method, char *type, char **class,
char **category, char **selector)
{
@@ -1154,15 +1112,11 @@ parse_method (char *method, char *type, char **class,
}
static void
-find_methods (struct symtab *symtab, char type,
- const char *class, const char *category,
- const char *selector, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+find_methods (char type, const char *class, const char *category,
+ const char *selector,
+ VEC (const_char_ptr) **symbol_names)
{
struct objfile *objfile = NULL;
- struct minimal_symbol *msymbol = NULL;
- struct block *block = NULL;
- struct symbol *sym = NULL;
char *symname = NULL;
@@ -1171,21 +1125,15 @@ find_methods (struct symtab *symtab, char type,
char *ncategory = NULL;
char *nselector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
static char *tmp = NULL;
static unsigned int tmplen = 0;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
-
- if (symtab)
- block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+ gdb_assert (symbol_names != NULL);
ALL_OBJFILES (objfile)
{
unsigned int *objc_csym;
+ struct minimal_symbol *msymbol = NULL;
/* The objfile_csym variable counts the number of ObjC methods
that this objfile defines. We save that count as a private
@@ -1202,7 +1150,6 @@ find_methods (struct symtab *symtab, char type,
ALL_OBJFILE_MSYMBOLS (objfile, msymbol)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- CORE_ADDR pc = SYMBOL_VALUE_ADDRESS (msymbol);
QUIT;
@@ -1216,18 +1163,8 @@ find_methods (struct symtab *symtab, char type,
/* Not a method name. */
continue;
- /* 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, pc,
- ¤t_target);
-
objfile_csym++;
- if (symtab)
- if (pc < BLOCK_START (block) || pc >= BLOCK_END (block))
- /* Not in the specified symtab. */
- continue;
-
/* Now that thinks are a bit sane, clean up the symname. */
while ((strlen (symname) + 1) >= tmplen)
{
@@ -1255,41 +1192,9 @@ find_methods (struct symtab *symtab, char type,
((nselector == NULL) || (strcmp (selector, nselector) != 0)))
continue;
- sym = find_pc_function (pc);
- if (sym != NULL)
- {
- const char *newsymname = SYMBOL_NATURAL_NAME (sym);
-
- if (strcmp (symname, newsymname) == 0)
- {
- /* Found a high-level method sym: swap it into the
- lower part of sym_arr (below num_debuggable). */
- if (syms != NULL)
- {
- syms[csym] = syms[cdebug];
- syms[cdebug] = sym;
- }
- csym++;
- cdebug++;
- }
- else
- {
- warning (
-"debugging symbol \"%s\" does not match minimal symbol (\"%s\"); ignoring",
- newsymname, symname);
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
- }
- else
- {
- /* Found a non-debuggable method symbol. */
- if (syms != NULL)
- syms[csym] = (struct symbol *) msymbol;
- csym++;
- }
+ VEC_safe_push (const_char_ptr, *symbol_names, symname);
}
+
if (objc_csym == NULL)
{
objc_csym = obstack_alloc (&objfile->objfile_obstack,
@@ -1301,38 +1206,79 @@ find_methods (struct symtab *symtab, char type,
/* Count of ObjC methods in this objfile should be constant. */
gdb_assert (*objc_csym == objfile_csym);
}
+}
+
+/* Uniquify a VEC of strings. */
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
+static void
+uniquify_strings (VEC (const_char_ptr) **strings)
+{
+ int ix;
+ const char *elem, *last = NULL;
+ int out;
+
+ qsort (VEC_address (const_char_ptr, *strings),
+ VEC_length (const_char_ptr, *strings),
+ sizeof (const_char_ptr),
+ compare_strings);
+ out = 0;
+ for (ix = 0; VEC_iterate (const_char_ptr, *strings, ix, elem); ++ix)
+ {
+ if (last == NULL || strcmp (last, elem) != 0)
+ {
+ /* Keep ELEM. */
+ VEC_replace (const_char_ptr, *strings, out, elem);
+ ++out;
+ }
+ last = elem;
+ }
+ VEC_truncate (const_char_ptr, *strings, out);
}
-char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug)
+/*
+ * Function: find_imps (char *selector, struct symbol **sym_arr)
+ *
+ * Input: a string representing a selector
+ * a pointer to an array of symbol pointers
+ * possibly a pointer to a symbol found by the caller.
+ *
+ * Output: number of methods that implement that selector. Side
+ * effects: The array of symbol pointers is filled with matching syms.
+ *
+ * By analogy with function "find_methods" (symtab.c), builds a list
+ * of symbols matching the ambiguous input, so that "decode_line_2"
+ * (symtab.c) can list them and ask the user to choose one or more.
+ * In this case the matches are objective c methods
+ * ("implementations") matching an objective c selector.
+ *
+ * Note that it is possible for a normal (c-style) function to have
+ * the same name as an objective c selector. To prevent the selector
+ * from eclipsing the function, we allow the caller (decode_line_1) to
+ * search for such a function first, and if it finds one, pass it in
+ * to us. We will then integrate it into the list. We also search
+ * for one here, among the minsyms.
+ *
+ * NOTE: if NUM_DEBUGGABLE is non-zero, the sym_arr will be divided
+ * into two parts: debuggable (struct symbol) syms, and
+ * non_debuggable (struct minimal_symbol) syms. The debuggable
+ * ones will come first, before NUM_DEBUGGABLE (which will thus
+ * be the index of the first non-debuggable one).
+ */
+
+char *
+find_imps (char *method, VEC (const_char_ptr) **symbol_names)
{
char type = '\0';
char *class = NULL;
char *category = NULL;
char *selector = NULL;
- unsigned int csym = 0;
- unsigned int cdebug = 0;
-
- unsigned int ncsym = 0;
- unsigned int ncdebug = 0;
-
char *buf = NULL;
char *tmp = NULL;
- gdb_assert (nsym != NULL);
- gdb_assert (ndebug != NULL);
+ int selector_case = 0;
- if (nsym != NULL)
- *nsym = 0;
- if (ndebug != NULL)
- *ndebug = 0;
+ gdb_assert (symbol_names != NULL);
buf = (char *) alloca (strlen (method) + 1);
strcpy (buf, method);
@@ -1340,99 +1286,37 @@ char *find_imps (struct symtab *symtab, struct block *block,
if (tmp == NULL)
{
- struct symbol *sym = NULL;
- struct minimal_symbol *msym = NULL;
-
strcpy (buf, method);
tmp = parse_selector (buf, &selector);
if (tmp == NULL)
return NULL;
- sym = lookup_symbol (selector, block, VAR_DOMAIN, 0);
- if (sym != NULL)
- {
- if (syms)
- syms[csym] = sym;
- csym++;
- cdebug++;
- }
-
- if (sym == NULL)
- msym = lookup_minimal_symbol (selector, 0, 0);
-
- if (msym != NULL)
- {
- if (syms)
- syms[csym] = (struct symbol *)msym;
- csym++;
- }
+ selector_case = 1;
}
- if (syms != NULL)
- find_methods (symtab, type, class, category, selector,
- syms + csym, &ncsym, &ncdebug);
- else
- find_methods (symtab, type, class, category, selector,
- NULL, &ncsym, &ncdebug);
-
- /* If we didn't find any methods, just return. */
- if (ncsym == 0 && ncdebug == 0)
- return method;
+ find_methods (type, class, category, selector, symbol_names);
- /* Take debug symbols from the second batch of symbols and swap them
- * with debug symbols from the first batch. Repeat until either the
- * second section is out of debug symbols or the first section is
- * full of debug symbols. Either way we have all debug symbols
- * packed to the beginning of the buffer.
- */
-
- if (syms != NULL)
+ /* If we hit the "selector" case, and we found some methods, then
+ add the selector itself as a symbol, if it exists. */
+ if (selector_case && !VEC_empty (const_char_ptr, *symbol_names))
{
- while ((cdebug < csym) && (ncdebug > 0))
+ struct symbol *sym = lookup_symbol (selector, NULL, VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (sym));
+ else
{
- struct symbol *s = NULL;
- /* First non-debugging symbol. */
- unsigned int i = cdebug;
- /* Last of second batch of debug symbols. */
- unsigned int j = csym + ncdebug - 1;
-
- s = syms[j];
- syms[j] = syms[i];
- syms[i] = s;
-
- /* We've moved a symbol from the second debug section to the
- first one. */
- cdebug++;
- ncdebug--;
+ struct minimal_symbol *msym = lookup_minimal_symbol (selector, 0, 0);
+
+ if (msym != NULL)
+ VEC_safe_push (const_char_ptr, *symbol_names,
+ SYMBOL_NATURAL_NAME (msym));
}
}
- csym += ncsym;
- cdebug += ncdebug;
-
- if (nsym != NULL)
- *nsym = csym;
- if (ndebug != NULL)
- *ndebug = cdebug;
-
- if (syms == NULL)
- return method + (tmp - buf);
-
- if (csym > 1)
- {
- /* Sort debuggable symbols. */
- if (cdebug > 1)
- qsort (syms, cdebug, sizeof (struct minimal_symbol *),
- compare_classes);
-
- /* Sort minimal_symbols. */
- if ((csym - cdebug) > 1)
- qsort (&syms[cdebug], csym - cdebug,
- sizeof (struct minimal_symbol *), compare_classes);
- }
- /* Terminate the sym_arr list. */
- syms[csym] = 0;
+ uniquify_strings (symbol_names);
return method + (tmp - buf);
}
diff --git a/gdb/objc-lang.h b/gdb/objc-lang.h
index ee4cc29..351af7b 100644
--- a/gdb/objc-lang.h
+++ b/gdb/objc-lang.h
@@ -21,6 +21,8 @@
#if !defined(OBJC_LANG_H)
#define OBJC_LANG_H
+#include "cp-support.h" /* For VEC (const_char_ptr) */
+
struct stoken;
struct value;
@@ -39,15 +41,7 @@ extern char *objc_demangle (const char *mangled, int options);
extern int find_objc_msgcall (CORE_ADDR pc, CORE_ADDR *new_pc);
-extern char *parse_selector (char *method, char **selector);
-
-extern char *parse_method (char *method, char *type,
- char **class, char **category,
- char **selector);
-
-extern char *find_imps (struct symtab *symtab, struct block *block,
- char *method, struct symbol **syms,
- unsigned int *nsym, unsigned int *ndebug);
+extern char *find_imps (char *method, VEC (const_char_ptr) **symbol_names);
extern struct value *value_nsstring (struct gdbarch *gdbarch,
char *ptr, int len);
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 6c4507d..c20fd78 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -125,13 +125,42 @@ require_partial_symbols (struct objfile *objfile, int verbose)
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, p)
-/* Lookup the partial symbol table of a source file named NAME.
- *If* there is no '/' in the name, a match after a '/'
- in the psymtab filename will also work. */
+/* Helper function for partial_map_symtabs_matching_filename that
+ expands the symtabs and calls the iterator. */
-static struct partial_symtab *
-lookup_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path)
+static int
+partial_map_expand_apply (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ struct partial_symtab *pst,
+ int (*callback) (struct symtab *, void *),
+ void *data)
+{
+ struct symtab *last_made = objfile->symtabs;
+
+ /* Don't visit already-expanded psymtabs. */
+ if (pst->readin)
+ return 0;
+
+ /* This may expand more than one symtab, and we want to iterate over
+ all of them. */
+ psymtab_to_symtab (pst);
+
+ return iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, last_made);
+}
+
+/* Implementation of the map_symtabs_matching_filename method. */
+
+static int
+partial_map_symtabs_matching_filename (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data)
{
struct partial_symtab *pst;
const char *name_basename = lbasename (name);
@@ -140,7 +169,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
/* Before we invoke realpath, which can get expensive when many
@@ -157,7 +188,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
if (pst->fullname != NULL
&& FILENAME_CMP (full_path, pst->fullname) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
@@ -172,7 +205,9 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
}
if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
{
- return pst;
+ if (partial_map_expand_apply (objfile, name, full_path, real_path,
+ pst, callback, data))
+ return 1;
}
}
}
@@ -183,29 +218,12 @@ lookup_partial_symtab (struct objfile *objfile, const char *name,
ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (lbasename (pst->filename), name) == 0)
- return (pst);
+ if (partial_map_expand_apply (objfile, name, full_path, real_path, pst,
+ callback, data))
+ return 1;
}
- return (NULL);
-}
-
-static int
-lookup_symtab_via_partial_symtab (struct objfile *objfile, const char *name,
- const char *full_path, const char *real_path,
- struct symtab **result)
-{
- struct partial_symtab *ps;
-
- ps = lookup_partial_symtab (objfile, name, full_path, real_path);
- if (!ps)
- return 0;
-
- if (ps->readin)
- error (_("Internal: readin %s pst for `%s' found when no symtab found."),
- ps->filename, name);
-
- *result = PSYMTAB_TO_SYMTAB (ps);
- return 1;
+ return 0;
}
/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
@@ -1304,7 +1322,7 @@ const struct quick_symbol_functions psym_functions =
objfile_has_psyms,
find_last_source_symtab_from_partial,
forget_cached_source_info_partial,
- lookup_symtab_via_partial_symtab,
+ partial_map_symtabs_matching_filename,
lookup_symbol_aux_psymtabs,
pre_expand_symtabs_matching_psymtabs,
print_psymtab_stats_for_objfile,
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index f76b1c7..b038e03 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -934,7 +934,7 @@ DEF_VEC_O (type_equality_entry_d);
the same, 0 otherwise. Handles NULLs properly. */
static int
-compare_strings (const char *s, const char *t)
+compare_maybe_null_strings (const char *s, const char *t)
{
if (s == NULL && t != NULL)
return 0;
@@ -970,9 +970,10 @@ check_types_equal (struct type *type1, struct type *type2,
|| TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
return Py_NE;
- if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_TAG_NAME (type1),
+ TYPE_TAG_NAME (type2)))
return Py_NE;
- if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+ if (!compare_maybe_null_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
return Py_NE;
if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
@@ -995,7 +996,8 @@ check_types_equal (struct type *type1, struct type *type2,
|| FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
|| FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
return Py_NE;
- if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_NAME (*field1),
+ FIELD_NAME (*field2)))
return Py_NE;
switch (FIELD_LOC_KIND (*field1))
{
@@ -1009,8 +1011,8 @@ check_types_equal (struct type *type1, struct type *type2,
return Py_NE;
break;
case FIELD_LOC_KIND_PHYSNAME:
- if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
- FIELD_STATIC_PHYSNAME (*field2)))
+ if (!compare_maybe_null_strings (FIELD_STATIC_PHYSNAME (*field1),
+ FIELD_STATIC_PHYSNAME (*field2)))
return Py_NE;
break;
case FIELD_LOC_KIND_DWARF_BLOCK:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 108e542..b898313 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -512,7 +512,7 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
{
copy = xstrdup (arg);
make_cleanup (xfree, copy);
- sals = decode_line_1 (©, 0, 0, 0, 0);
+ sals = decode_line_1 (©, 0, 0, 0);
make_cleanup (xfree, sals.sals);
}
else
diff --git a/gdb/skip.c b/gdb/skip.c
index 9f15c2f..11c1956 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -164,7 +164,7 @@ skip_function_command (char *arg, int from_tty)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&arg, 1, 0, 0, 0);
+ sals = decode_line_1 (&arg, 1, 0, 0);
}
if (decode_exception.reason < 0)
@@ -514,7 +514,7 @@ skip_re_set (void)
TRY_CATCH (decode_exception, RETURN_MASK_ERROR)
{
- sals = decode_line_1 (&func_name, 1, 0, 0, 0);
+ sals = decode_line_1 (&func_name, 1, 0, 0);
}
if (decode_exception.reason >= 0
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 888aa34..21efbdf 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -28,8 +28,6 @@
#include "gdb_string.h"
-DEF_VEC_I(CORE_ADDR);
-
/* Private data for each loaded library. */
struct lm_info
{
diff --git a/gdb/source.c b/gdb/source.c
index 77df541..49e9e49 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1413,12 +1413,14 @@ line_info (char *arg, int from_tty)
struct symtab_and_line sal;
CORE_ADDR start_pc, end_pc;
int i;
+ struct cleanup *cleanups;
init_sal (&sal); /* initialize to zeroes */
if (arg == 0)
{
sal.symtab = current_source_symtab;
+ sal.pspace = current_program_space;
sal.line = last_line_listed;
sals.nelts = 1;
sals.sals = (struct symtab_and_line *)
@@ -1432,11 +1434,15 @@ line_info (char *arg, int from_tty)
dont_repeat ();
}
+ cleanups = make_cleanup (xfree, sals.sals);
+
/* C++ More than one line may have been specified, as when the user
specifies an overloaded function name. Print info on them all. */
for (i = 0; i < sals.nelts; i++)
{
sal = sals.sals[i];
+ if (sal.pspace != current_program_space)
+ continue;
if (sal.symtab == 0)
{
@@ -1502,7 +1508,7 @@ line_info (char *arg, int from_tty)
printf_filtered (_("Line number %d is out of range for \"%s\".\n"),
sal.line, sal.symtab->filename);
}
- xfree (sals.sals);
+ do_cleanups (cleanups);
}
\f
/* Commands to search the source file for a regexp. */
diff --git a/gdb/stack.c b/gdb/stack.c
index 9136daa..48c1c27 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2444,20 +2444,25 @@ func_command (char *arg, int from_tty)
int i;
int level = 1;
struct function_bounds *func_bounds = NULL;
+ struct cleanup *cleanups;
if (arg != NULL)
return;
frame = parse_frame_specification ("0");
sals = decode_line_spec (arg, 1);
+ cleanups = make_cleanup (xfree, sals.sals);
func_bounds = (struct function_bounds *) xmalloc (
sizeof (struct function_bounds) * sals.nelts);
+ make_cleanup (xfree, func_bounds);
for (i = 0; (i < sals.nelts && !found); i++)
{
- if (sals.sals[i].pc == 0
- || find_pc_partial_function (sals.sals[i].pc, NULL,
- &func_bounds[i].low,
- &func_bounds[i].high) == 0)
+ if (sals.sals[i].pspace != current_program_space)
+ func_bounds[i].low = func_bounds[i].high = 0;
+ else if (sals.sals[i].pc == 0
+ || find_pc_partial_function (sals.sals[i].pc, NULL,
+ &func_bounds[i].low,
+ &func_bounds[i].high) == 0)
{
func_bounds[i].low = func_bounds[i].high = 0;
}
@@ -2476,8 +2481,7 @@ func_command (char *arg, int from_tty)
}
while (!found && level == 0);
- if (func_bounds)
- xfree (func_bounds);
+ do_cleanups (cleanups);
if (!found)
printf_filtered (_("'%s' not within current stack frame.\n"), arg);
diff --git a/gdb/symfile.h b/gdb/symfile.h
index accd20e..dfe5042 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -152,22 +152,24 @@ struct quick_symbol_functions
/* Forget all cached full file names for OBJFILE. */
void (*forget_cached_source_info) (struct objfile *objfile);
- /* Look up the symbol table, in OBJFILE, of a source file named
- NAME. If there is no '/' in the name, a match after a '/' in the
- symbol table's file name will also work. FULL_PATH is the
- absolute file name, and REAL_PATH is the same, run through
- gdb_realpath.
-
- If no such symbol table can be found, returns 0.
-
- Otherwise, sets *RESULT to the symbol table and returns 1. This
- might return 1 and set *RESULT to NULL if the requested file is
- an include file that does not have a symtab of its own. */
- int (*lookup_symtab) (struct objfile *objfile,
- const char *name,
- const char *full_path,
- const char *real_path,
- struct symtab **result);
+ /* Expand and iterate over each "partial" symbol table in OBJFILE
+ where the source file is named NAME.
+
+ If there is no '/' in the name, a match after a '/' in the symbol
+ table's file name will also work. FULL_PATH is the absolute file
+ name, and REAL_PATH is the same, run through gdb_realpath.
+
+ If a match is found, the "partial" symbol table is expanded.
+ Then, this calls iterate_over_some_symtabs (or equivalent) over
+ all newly-created symbol tables, passing CALLBACK and DATA to it.
+ The result of this call is returned. */
+ int (*map_symtabs_matching_filename) (struct objfile *objfile,
+ const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *,
+ void *),
+ void *data);
/* Check to see if the symbol is defined in a "partial" symbol table
of OBJFILE. KIND should be either GLOBAL_BLOCK or STATIC_BLOCK,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3d94e6b..f55ca1c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -81,7 +81,7 @@ static void sources_info (char *, int);
static void output_source_filename (const char *, int *);
-static int find_line_common (struct linetable *, int, int *);
+static int find_line_common (struct linetable *, int, int *, int);
static struct symbol *lookup_symbol_aux (const char *name,
const struct block *block,
@@ -147,44 +147,38 @@ multiple_symbols_select_mode (void)
const struct block *block_found;
-/* Check for a symtab of a specific name; first in symtabs, then in
- psymtabs. *If* there is no '/' in the name, a match after a '/'
- in the symtab filename will also work. */
+/* Check for a symtab of a specific name by searching some symtabs.
+ This is a helper function for callbacks of iterate_over_symtabs.
-struct symtab *
-lookup_symtab (const char *name)
+ The return value, NAME, FULL_PATH, REAL_PATH, CALLBACK, and DATA
+ are identical to the `map_symtabs_matching_filename' method of
+ quick_symbol_functions.
+
+ FIRST and AFTER_LAST indicate the range of symtabs to search.
+ AFTER_LAST is one past the last symtab to search; NULL means to
+ search until the end of the list. */
+
+int
+iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last)
{
- int found;
struct symtab *s = NULL;
- struct objfile *objfile;
- char *real_path = NULL;
- char *full_path = NULL;
struct cleanup *cleanup;
const char* base_name = lbasename (name);
- cleanup = make_cleanup (null_cleanup, NULL);
-
- /* Here we are interested in canonicalizing an absolute path, not
- absolutizing a relative path. */
- if (IS_ABSOLUTE_PATH (name))
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- full_path = xfullpath (name);
- make_cleanup (xfree, full_path);
- real_path = gdb_realpath (name);
- make_cleanup (xfree, real_path);
- }
-
-got_symtab:
-
- /* First, search for an exact match. */
-
- ALL_SYMTABS (objfile, s)
- {
- if (FILENAME_CMP (name, s->filename) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ if (FILENAME_CMP (name, s->filename) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
/* Before we invoke realpath, which can get expensive when many
files are involved, do a quick comparison of the basenames. */
@@ -201,8 +195,8 @@ got_symtab:
if (fp != NULL && FILENAME_CMP (full_path, fp) == 0)
{
- do_cleanups (cleanup);
- return s;
+ if (callback (s, data))
+ return 1;
}
}
@@ -216,62 +210,114 @@ got_symtab:
make_cleanup (xfree, rp);
if (FILENAME_CMP (real_path, rp) == 0)
- {
- do_cleanups (cleanup);
- return s;
- }
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
- }
+ }
/* Now, search for a matching tail (only if name doesn't have any dirs). */
if (lbasename (name) == name)
- ALL_SYMTABS (objfile, s)
{
- if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ for (s = first; s != NULL && s != after_last; s = s->next)
{
- do_cleanups (cleanup);
- return s;
+ if (FILENAME_CMP (lbasename (s->filename), name) == 0)
+ {
+ if (callback (s, data))
+ return 1;
+ }
}
}
+ return 0;
+}
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+ psymtabs. *If* there is no '/' in the name, a match after a '/'
+ in the symtab filename will also work.
+
+ Calls CALLBACK with each symtab that is found and with the supplied
+ DATA. If CALLBACK returns true, the search stops. */
+
+void
+iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data)
+{
+ struct symtab *s = NULL;
+ struct objfile *objfile;
+ char *real_path = NULL;
+ char *full_path = NULL;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+
+ /* Here we are interested in canonicalizing an absolute path, not
+ absolutizing a relative path. */
+ if (IS_ABSOLUTE_PATH (name))
+ {
+ full_path = xfullpath (name);
+ make_cleanup (xfree, full_path);
+ real_path = gdb_realpath (name);
+ make_cleanup (xfree, real_path);
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ if (iterate_over_some_symtabs (name, full_path, real_path, callback, data,
+ objfile->symtabs, NULL))
+ {
+ do_cleanups (cleanups);
+ return;
+ }
+ }
+
/* Same search rules as above apply here, but now we look thru the
psymtabs. */
- found = 0;
ALL_OBJFILES (objfile)
{
if (objfile->sf
- && objfile->sf->qf->lookup_symtab (objfile, name, full_path, real_path,
- &s))
+ && objfile->sf->qf->map_symtabs_matching_filename (objfile,
+ name,
+ full_path,
+ real_path,
+ callback,
+ data))
{
- found = 1;
- break;
+ do_cleanups (cleanups);
+ return;
}
}
- if (s != NULL)
- {
- do_cleanups (cleanup);
- return s;
- }
- if (!found)
- {
- do_cleanups (cleanup);
- return NULL;
- }
+ do_cleanups (cleanups);
+}
+
+/* The callback function used by lookup_symtab. */
+
+static int
+lookup_symtab_callback (struct symtab *symtab, void *data)
+{
+ struct symtab **result_ptr = data;
- /* At this point, we have located the psymtab for this file, but
- the conversion to a symtab has failed. This usually happens
- when we are looking up an include file. In this case,
- PSYMTAB_TO_SYMTAB doesn't return a symtab, even though one has
- been created. So, we need to run through the symtabs again in
- order to find the file.
- XXX - This is a crock, and should be fixed inside of the
- symbol parsing routines. */
- goto got_symtab;
+ *result_ptr = symtab;
+ return 1;
}
+
+/* A wrapper for iterate_over_symtabs that returns the first matching
+ symtab, or NULL. */
+
+struct symtab *
+lookup_symtab (const char *name)
+{
+ struct symtab *result = NULL;
+
+ iterate_over_symtabs (name, lookup_symtab_callback, &result);
+ return result;
+}
+
\f
/* Mangle a GDB method stub type. This actually reassembles the pieces of the
full method name, which consist of the class name (from T), the unadorned
@@ -1006,33 +1052,16 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
return sym;
}
-/* Find the definition for a specified symbol name NAME
- in domain DOMAIN, visible from lexical block BLOCK.
- Returns the struct symbol pointer, or zero if no symbol is found.
- C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
- NAME is a field of the current implied argument `this'. If so set
- *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
- BLOCK_FOUND is set to the block in which NAME is found (in the case of
- a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
-
-/* This function has a bunch of loops in it and it would seem to be
- attractive to put in some QUIT's (though I'm not really sure
- whether it can run long enough to be really important). But there
- are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
- that there is C++ code below which can error(), but that probably
- doesn't affect these calls since they are looking for a known
- variable and thus can probably assume it will never hit the C++
- code). */
+/* Compute the demangled form of NAME as used by the various symbol
+ lookup functions. The result is stored in *RESULT_NAME. Returns a
+ cleanup which can be used to clean up the result. */
-struct symbol *
-lookup_symbol_in_language (const char *name, const struct block *block,
- const domain_enum domain, enum language lang,
- int *is_a_field_of_this)
+struct cleanup *
+demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name)
{
char *demangled_name = NULL;
const char *modified_name = NULL;
- struct symbol *returnval;
struct cleanup *cleanup = make_cleanup (null_cleanup, 0);
modified_name = name;
@@ -1079,6 +1108,38 @@ lookup_symbol_in_language (const char *name, const struct block *block,
}
}
+ *result_name = modified_name;
+ return cleanup;
+}
+
+/* Find the definition for a specified symbol name NAME
+ in domain DOMAIN, visible from lexical block BLOCK.
+ Returns the struct symbol pointer, or zero if no symbol is found.
+ C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+ NAME is a field of the current implied argument `this'. If so set
+ *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero.
+ BLOCK_FOUND is set to the block in which NAME is found (in the case of
+ a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+/* This function has a bunch of loops in it and it would seem to be
+ attractive to put in some QUIT's (though I'm not really sure
+ whether it can run long enough to be really important). But there
+ are a few calls for which it would appear to be bad news to quit
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
+
+struct symbol *
+lookup_symbol_in_language (const char *name, const struct block *block,
+ const domain_enum domain, enum language lang,
+ int *is_a_field_of_this)
+{
+ const char *modified_name;
+ struct symbol *returnval;
+ struct cleanup *cleanup = demangle_for_lookup (name, lang, &modified_name);
+
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
@@ -1771,6 +1832,44 @@ lookup_block_symbol (const struct block *block, const char *name,
}
}
+/* Iterate over the symbols named NAME, matching DOMAIN, starting with
+ BLOCK.
+
+ For each symbol that matches, CALLBACK is called. The symbol and
+ DATA are passed to the callback.
+
+ If CALLBACK returns zero, the iteration ends. Otherwise, the
+ search continues. This function iterates upward through blocks.
+ When the outermost block has been finished, the function
+ returns. */
+
+void
+iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter);
+ sym != NULL;
+ sym = dict_iter_name_next (name, &iter))
+ {
+ if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+ SYMBOL_DOMAIN (sym), domain))
+ {
+ if (!callback (sym, data))
+ return;
+ }
+ }
+
+ block = BLOCK_SUPERBLOCK (block);
+ }
+}
+
/* Find the symtab associated with PC and SECTION. Look through the
psymtabs and read in another symtab if necessary. */
@@ -2196,7 +2295,7 @@ find_line_symtab (struct symtab *symtab, int line,
/* First try looking it up in the given symtab. */
best_linetable = LINETABLE (symtab);
best_symtab = symtab;
- best_index = find_line_common (best_linetable, line, &exact);
+ best_index = find_line_common (best_linetable, line, &exact, 0);
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
@@ -2241,7 +2340,7 @@ find_line_symtab (struct symtab *symtab, int line,
&& FILENAME_CMP (symtab->fullname, s->fullname) != 0)
continue;
l = LINETABLE (s);
- ind = find_line_common (l, line, &exact);
+ ind = find_line_common (l, line, &exact, 0);
if (ind >= 0)
{
if (exact)
@@ -2272,6 +2371,114 @@ done:
return best_symtab;
}
+
+/* qsort comparison function for use by find_pcs_for_symtab_line. */
+
+static int
+compare_core_addrs (const void *a, const void *b)
+{
+ const CORE_ADDR *ca = a;
+ const CORE_ADDR *cb = b;
+
+ return (int) (ca - cb);
+}
+
+/* Return true if an inexact match at PC, in SYMTAB, is valid.
+ REQUESTED_LINE is the line which the user requested. This uses a
+ heuristic to decide whether the line that was actually found is
+ suitable. */
+
+static int
+validate_inexact_match (struct symtab *symtab, CORE_ADDR pc,
+ int requested_line)
+{
+ struct block *block = block_for_pc (pc);
+ struct symbol *sym;
+
+ /* If we can't find it, conservatively say it is ok. It is better
+ to break at too many locations than too few. */
+ if (!block)
+ return 1;
+ sym = block_containing_function (block);
+ /* If the found symbol is in a different symtab, conservatively say
+ it is ok. This handles odd cases like having a function's body
+ in an include file. Otherwise, if the symtabs are the same, then
+ the requested line must appear after the start of the
+ function. */
+ return SYMBOL_SYMTAB (sym) != symtab || requested_line >= SYMBOL_LINE (sym);
+}
+
+/* Given SYMTAB, return one PC per function in the symtab that exactly
+ matches LINE. Returns NULL if none matched. */
+
+VEC (CORE_ADDR) *
+find_pcs_for_symtab_line (struct symtab *symtab, int line)
+{
+ VEC (CORE_ADDR) *result = NULL;
+ int start = 0, ix;
+ struct symbol *previous_function = NULL;
+
+ /* First, collect all the PCs that are at this line. */
+ while (1)
+ {
+ int was_exact;
+ int idx;
+
+ idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+ if (idx < 0)
+ break;
+
+ if (!was_exact)
+ {
+ if (VEC_empty (CORE_ADDR, result)
+ && validate_inexact_match (symtab,
+ LINETABLE (symtab)->item[idx].pc,
+ line))
+ {
+ /* We only found an inexact match. So, redo the search
+ for the found line. */
+ line = LINETABLE (symtab)->item[idx].line;
+ start = 0;
+ continue;
+ }
+ break;
+ }
+
+ VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+ start = idx + 1;
+ }
+
+ if (VEC_empty (CORE_ADDR, result))
+ return result;
+
+ qsort (VEC_address (CORE_ADDR, result), VEC_length (CORE_ADDR, result),
+ sizeof (CORE_ADDR), compare_core_addrs);
+
+ /* Remove all duplicate entries from the result. That is, each
+ function should only appear a single time. */
+ for (ix = 0; ix < VEC_length (CORE_ADDR, result); )
+ {
+ struct symbol *sym;
+ struct block *block;
+
+ block = block_for_pc (VEC_index (CORE_ADDR, result, ix));
+ sym = block ? block_containing_function (block) : NULL;
+
+ if (sym == NULL || sym == previous_function)
+ VEC_ordered_remove (CORE_ADDR, result, ix);
+ else
+ {
+ previous_function = sym;
+ ++ix;
+ }
+ }
+
+ if (VEC_length (CORE_ADDR, result) == 0)
+ VEC_free (CORE_ADDR, result);
+
+ return result;
+}
+
\f
/* Set the PC value for a given source file and line number and return true.
Returns zero for invalid line number (and sets the PC to 0).
@@ -2340,12 +2547,13 @@ find_line_pc_range (struct symtab_and_line sal, CORE_ADDR *startptr,
/* Given a line table and a line number, return the index into the line
table for the pc of the nearest line whose number is >= the specified one.
Return -1 if none is found. The value is >= 0 if it is an index.
+ START is the index at which to start searching the line table.
Set *EXACT_MATCH nonzero if the value returned is an exact match. */
static int
find_line_common (struct linetable *l, int lineno,
- int *exact_match)
+ int *exact_match, int start)
{
int i;
int len;
@@ -2365,7 +2573,7 @@ find_line_common (struct linetable *l, int lineno,
return -1;
len = l->nitems;
- for (i = 0; i < len; i++)
+ for (i = start; i < len; i++)
{
struct linetable_entry *item = &(l->item[i]);
@@ -4531,8 +4739,7 @@ decode_line_spec (char *string, int funfirstline)
cursal = get_current_source_symtab_and_line ();
sals = decode_line_1 (&string, funfirstline,
- cursal.symtab, cursal.line,
- NULL);
+ cursal.symtab, cursal.line);
if (*string)
error (_("Junk at end of line specification: %s"), string);
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 39a61f4..8bc2af9 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -22,6 +22,8 @@
#if !defined (SYMTAB_H)
#define SYMTAB_H 1
+#include "vec.h"
+
/* Opaque declarations. */
struct ui_file;
struct frame_info;
@@ -1056,6 +1058,12 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern void iterate_over_minimal_symbols (struct objfile *objf,
+ const char *name,
+ void (*callback) (struct minimal_symbol *,
+ void *),
+ void *user_data);
+
extern int in_gnu_ifunc_stub (CORE_ADDR pc);
/* Functions for resolving STT_GNU_IFUNC symbols which are implemented only
@@ -1308,4 +1316,30 @@ struct objfile *lookup_objfile_from_block (const struct block *block);
extern int basenames_may_differ;
+int iterate_over_some_symtabs (const char *name,
+ const char *full_path,
+ const char *real_path,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data,
+ struct symtab *first,
+ struct symtab *after_last);
+
+void iterate_over_symtabs (const char *name,
+ int (*callback) (struct symtab *symtab,
+ void *data),
+ void *data);
+
+DEF_VEC_I (CORE_ADDR);
+
+VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line);
+
+void iterate_over_symbols (const struct block *block, const char *name,
+ const domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data);
+
+struct cleanup *demangle_for_lookup (const char *name, enum language lang,
+ const char **result_name);
+
#endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/Makefile.in b/gdb/testsuite/Makefile.in
index 8b22324..d3c9cfc 100644
--- a/gdb/testsuite/Makefile.in
+++ b/gdb/testsuite/Makefile.in
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cell gdb.cp gdb.disasm \
gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \
- gdb.java gdb.mi gdb.modula2 gdb.multi \
+ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \
gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \
gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \
$(SUBDIRS)
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index 82206b3..fb70b3d 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -3448,7 +3448,7 @@ done
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4166,6 +4166,7 @@ do
"gdb.hp/gdb.aCC/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.aCC/Makefile" ;;
"gdb.hp/gdb.compat/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.compat/Makefile" ;;
"gdb.hp/gdb.defects/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/gdb.defects/Makefile" ;;
+ "gdb.linespec/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.linespec/Makefile" ;;
"gdb.mi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.mi/Makefile" ;;
"gdb.modula2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.modula2/Makefile" ;;
"gdb.multi/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.multi/Makefile" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 8631442..121fd37 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -95,7 +95,7 @@ AC_OUTPUT([Makefile \
gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
- gdb.hp/gdb.defects/Makefile \
+ gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \
gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \
diff --git a/gdb/testsuite/gdb.base/break.exp b/gdb/testsuite/gdb.base/break.exp
index 92fcc69..c5885ba 100644
--- a/gdb/testsuite/gdb.base/break.exp
+++ b/gdb/testsuite/gdb.base/break.exp
@@ -540,8 +540,9 @@ gdb_test_multiple "catch exec" "$name" {
# Verify that GDB responds gracefully when asked to set a breakpoint
# on a nonexistent source line.
#
+gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in file .*" \
+ "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/list.exp b/gdb/testsuite/gdb.base/list.exp
index 5b9fe15..d4935ee 100644
--- a/gdb/testsuite/gdb.base/list.exp
+++ b/gdb/testsuite/gdb.base/list.exp
@@ -489,7 +489,7 @@ proc test_list_filename_and_function {} {
gdb_test "list foobar.c:main" "No source file named foobar.c.|Location not found" "list filename:function; nonexistant file"
- gdb_test "list list0.h:foobar" "Function \"foobar\" not defined.|Location not found" "list filename:function; nonexistant function"
+ gdb_test "list list0.h:foobar" "Function \"foobar\" not defined in \"list0.h\"." "list filename:function; nonexistant function"
}
diff --git a/gdb/testsuite/gdb.base/sepdebug.exp b/gdb/testsuite/gdb.base/sepdebug.exp
index 1a9072d..bb0b914 100644
--- a/gdb/testsuite/gdb.base/sepdebug.exp
+++ b/gdb/testsuite/gdb.base/sepdebug.exp
@@ -337,7 +337,8 @@ gdb_test_multiple "catch exec" $name {
# on a nonexistent source line.
#
-gdb_test "break 999" "No line 999 in file .*" \
+gdb_test_no_output "set breakpoint pending off"
+gdb_test "break 999" "No line 999 in the current file." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
diff --git a/gdb/testsuite/gdb.base/solib-symbol.exp b/gdb/testsuite/gdb.base/solib-symbol.exp
index aa723c6..d402ebb 100644
--- a/gdb/testsuite/gdb.base/solib-symbol.exp
+++ b/gdb/testsuite/gdb.base/solib-symbol.exp
@@ -46,11 +46,6 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_load_shlibs $binfile_lib
-if ![runto_main] then {
- fail "Can't run to main"
- return 0
-}
-
# Set a breakpoint in the binary.
gdb_test "br foo2" \
"Breakpoint.*file.*${testfile}\\.c.*" \
@@ -58,6 +53,11 @@ gdb_test "br foo2" \
delete_breakpoints
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
# Break in the library.
gdb_test "br foo" \
"Breakpoint.*file.*${libname}\\.c.*" \
@@ -67,9 +67,9 @@ gdb_test "continue" \
"Continuing.*" \
"continue"
-# This symbol is now looked up in the ELF library.
+# This symbol is now looked up in the ELF library and the binary.
gdb_test "br foo2" \
- "Breakpoint.*file.*${libname}\\.c.*" \
+ "Breakpoint.*: foo2. .2 locations..*" \
"foo2 in mdlib"
gdb_exit
diff --git a/gdb/testsuite/gdb.base/solib-weak.exp b/gdb/testsuite/gdb.base/solib-weak.exp
index 1f23aa2..52fd72d 100644
--- a/gdb/testsuite/gdb.base/solib-weak.exp
+++ b/gdb/testsuite/gdb.base/solib-weak.exp
@@ -101,15 +101,6 @@ proc do_test { lib1opts lib2opts lib1first } {
gdb_breakpoint "bar"
- # If the library which will be used is compiled without debugging
- # information, GDB will pick the wrong copy of "bar", i.e. the one
- # with debugging information.
-
- if {(${lib1opts} == "" && ${lib2opts} != "" && ${lib1first} == 1)
- || (${lib1opts} != "" && ${lib2opts} == "" && ${lib1first} == 0)} {
- setup_kfail gdb/1824 *-*-*
- }
-
gdb_test "continue" "Breakpoint .* \\.?bar .*${expected_file}\\..*" \
"run to breakpoint - $testopts"
}
diff --git a/gdb/testsuite/gdb.cp/mb-ctor.exp b/gdb/testsuite/gdb.cp/mb-ctor.exp
index 6a99175..0438424 100644
--- a/gdb/testsuite/gdb.cp/mb-ctor.exp
+++ b/gdb/testsuite/gdb.cp/mb-ctor.exp
@@ -50,13 +50,13 @@ if ![runto_main] then {
# and a condition.
gdb_test "break 'Derived::Derived(int)'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::Derived.int.. \\(2 locations\\).*" \
"set-breakpoint at ctor"
gdb_breakpoint [gdb_get_line_number "set breakpoint here"]
gdb_test "break 'Derived::~Derived()'" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: Derived::~Derived... \\(2 locations\\).*" \
"set-breakpoint at dtor"
gdb_test "continue" \
diff --git a/gdb/testsuite/gdb.cp/mb-inline.exp b/gdb/testsuite/gdb.cp/mb-inline.exp
index d670b56..05b378c 100644
--- a/gdb/testsuite/gdb.cp/mb-inline.exp
+++ b/gdb/testsuite/gdb.cp/mb-inline.exp
@@ -62,7 +62,7 @@ set bp_location [gdb_get_line_number "set breakpoint here" $hdrfile]
# Set a breakpoint with multiple locations.
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set breakpoint"
gdb_run_cmd
@@ -128,7 +128,7 @@ if { ![runto_main] } {
}
gdb_test "break $hdrfile:$bp_location" \
- "Breakpoint.*at.* file .*$hdrfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $hdrfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/mb-templates.exp b/gdb/testsuite/gdb.cp/mb-templates.exp
index 80c080b..933d690 100644
--- a/gdb/testsuite/gdb.cp/mb-templates.exp
+++ b/gdb/testsuite/gdb.cp/mb-templates.exp
@@ -52,7 +52,7 @@ set bp_location [gdb_get_line_number "set breakpoint here"]
# and a condition.
gdb_test "break $srcfile:$bp_location if i==1" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"initial condition: set breakpoint"
gdb_run_cmd
@@ -80,7 +80,7 @@ gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"separate condition: set breakpoint"
gdb_test_no_output "condition 1 i==1" \
@@ -177,7 +177,7 @@ if { ![runto_main] } {
}
gdb_test "break $srcfile:$bp_location" \
- "Breakpoint.*at.* file .*$srcfile, line.*\\(2 locations\\).*" \
+ "Breakpoint.*at.*: $srcfile:$bp_location. \\(2 locations\\).*" \
"set multi_line_foo breakpoint"
gdb_test "continue" \
".*Breakpoint.*multi_line_foo<int> \\(i=0\\).*" \
diff --git a/gdb/testsuite/gdb.cp/method2.exp b/gdb/testsuite/gdb.cp/method2.exp
index 2fa4169..29a387d 100644
--- a/gdb/testsuite/gdb.cp/method2.exp
+++ b/gdb/testsuite/gdb.cp/method2.exp
@@ -51,7 +51,7 @@ proc test_break { lang } {
"setting language $lang"
gdb_test_multiple "break A::method" "breaking in method ($lang)" {
- -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. A::method\\(A\\*\\) at .*\[\r\n\]*.3. A::method\\(int\\) at .*\[\r\n\]*\[\r\n\]*.4. A::method\\(\\) at .*\[\r\n\]*> $" {
+ -re ".0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. .*:A::method\\(A\\*\\)\[\r\n\]*.3. .*:A::method\\(int\\)\[\r\n\]*.4. .*:A::method\\(\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"breaking in method ($lang)"
diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp
index f5d4051..f5b41ab 100644
--- a/gdb/testsuite/gdb.cp/ovldbreak.exp
+++ b/gdb/testsuite/gdb.cp/ovldbreak.exp
@@ -130,18 +130,18 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} {
set menu_overload1arg "\\\[0\\\] cancel\r\n"
append menu_overload1arg "\\\[1\\\] all\r\n"
-append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n"
-append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n"
-append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n"
-append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n"
-append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n"
-append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n"
-append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n"
-append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n"
-append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n"
-append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n"
-append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n"
-append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n"
+append menu_overload1arg "\\\[2\\\] .*$srcfile:foo::overload1arg\\(double\\)\r\n"
+append menu_overload1arg "\\\[3\\\] .*$srcfile:foo::overload1arg\\(float\\)\r\n"
+append menu_overload1arg "\\\[4\\\] .*$srcfile:foo::overload1arg\\((unsigned long|long unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[5\\\] .*$srcfile:foo::overload1arg\\(long( int)?\\)\r\n"
+append menu_overload1arg "\\\[6\\\] .*$srcfile:foo::overload1arg\\((unsigned int|unsigned)\\)\r\n"
+append menu_overload1arg "\\\[7\\\] .*$srcfile:foo::overload1arg\\(int\\)\r\n"
+append menu_overload1arg "\\\[8\\\] .*$srcfile:foo::overload1arg\\((unsigned short|short unsigned)( int)?\\)\r\n"
+append menu_overload1arg "\\\[9\\\] .*$srcfile:foo::overload1arg\\(short( int)?\\)\r\n"
+append menu_overload1arg "\\\[10\\\] .*$srcfile:foo::overload1arg\\(unsigned char\\)\r\n"
+append menu_overload1arg "\\\[11\\\] .*$srcfile:foo::overload1arg\\(signed char\\)\r\n"
+append menu_overload1arg "\\\[12\\\] .*$srcfile:foo::overload1arg\\(char\\)\r\n"
+append menu_overload1arg "\\\[13\\\] .*$srcfile:foo::overload1arg\\((void|)\\)\r\n"
append menu_overload1arg "> $"
# Set multiple-symbols to "ask", to allow us to test the use
@@ -279,7 +279,7 @@ gdb_expect {
# Choose all.
send_gdb "1\n"
gdb_expect {
- -re "Breakpoint $decimal at $hex: file.*$srcfile, line 121.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 120.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 119.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 118.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 117.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 116.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 115.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 114.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 113.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 112.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 111.\r\nBreakpoint $decimal at $hex: file.*$srcfile, line 110.\r\nwarning: Multiple breakpoints were set.\r\nUse the .delete. command to delete unwanted breakpoints.\r\n$gdb_prompt $" {
+ -re "Breakpoint $decimal at $hex: foo::overload1arg. .12 locations.\r\n.*$gdb_prompt $" {
pass "set bp on overload1arg all"
}
-re ".*$gdb_prompt $" {
@@ -306,18 +306,19 @@ gdb_expect {
gdb_test "info break" \
"Num Type\[\t \]+Disp Enb Address\[\t \]+What.*
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
-\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
+\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+<MULTIPLE>\[\t \]*\r
+\[0-9\]+.1\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r
+\[0-9\]+.2\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r
+\[0-9\]+.3\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r
+\[0-9\]+.4\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r
+\[0-9\]+.5\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r
+\[0-9\]+.6\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r
+\[0-9\]+.7\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r
+\[0-9\]+.8\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r
+\[0-9\]+.9\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r
+\[0-9\]+.10\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r
+\[0-9\]+.11\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r
+\[0-9\]+.12\[\t \]+y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \
"breakpoint info (after setting on all)"
@@ -333,10 +334,10 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
send_gdb "continue\n"
gdb_expect {
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}(, )?${actuals}\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
pass "continue to bp overloaded : ${argtype}"
}
- -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, (${hex} in )?foo::overload1arg(\\(${argtype}\\))? \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
+ -re "Continuing.\r\n\r\nBreakpoint ${bpnumber}, foo::overload1arg \\(this=${hex}, arg=.*\\) at.*${srcfile}:${decimal}\r\n${decimal}\[\t \]+int foo::overload1arg \\(${argtype}( arg)?\\).*\r\n.*$gdb_prompt $" {
if $might_kfail {
kfail "gdb/1025" "continue to bp overloaded : ${argtype}"
} else {
@@ -352,17 +353,17 @@ proc continue_to_bp_overloaded {might_kfail bpnumber argtype actuals} {
}
}
-continue_to_bp_overloaded 0 25 "(void|)" ""
-continue_to_bp_overloaded 1 24 "char" "arg=2 \\'\\\\002\\'"
-continue_to_bp_overloaded 1 23 "signed char" "arg=3 \\'\\\\003\\'"
-continue_to_bp_overloaded 1 22 "unsigned char" "arg=4 \\'\\\\004\\'"
-continue_to_bp_overloaded 1 21 "short" "arg=5"
-continue_to_bp_overloaded 1 20 "unsigned short" "arg=6"
-continue_to_bp_overloaded 0 19 "int" "arg=7"
-continue_to_bp_overloaded 0 18 "(unsigned|unsigned int)" "arg=8"
-continue_to_bp_overloaded 0 17 "long" "arg=9"
-continue_to_bp_overloaded 0 16 "unsigned long" "arg=10"
-continue_to_bp_overloaded 0 15 "float" "arg=100"
+continue_to_bp_overloaded 0 14 "(void|)" ""
+continue_to_bp_overloaded 1 14 "char" "arg=2 \\'\\\\002\\'"
+continue_to_bp_overloaded 1 14 "signed char" "arg=3 \\'\\\\003\\'"
+continue_to_bp_overloaded 1 14 "unsigned char" "arg=4 \\'\\\\004\\'"
+continue_to_bp_overloaded 1 14 "short" "arg=5"
+continue_to_bp_overloaded 1 14 "unsigned short" "arg=6"
+continue_to_bp_overloaded 0 14 "int" "arg=7"
+continue_to_bp_overloaded 0 14 "(unsigned|unsigned int)" "arg=8"
+continue_to_bp_overloaded 0 14 "long" "arg=9"
+continue_to_bp_overloaded 0 14 "unsigned long" "arg=10"
+continue_to_bp_overloaded 0 14 "float" "arg=100"
continue_to_bp_overloaded 1 14 "double" "arg=200"
# Test breaking on an overloaded function when multiple-symbols
@@ -375,7 +376,7 @@ gdb_test "break foo::foofunc" \
# is set to "all"
gdb_test_no_output "set multiple-symbols all"
gdb_test "break foo::foofunc" \
- "Breakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nBreakpoint \[0-9\]+ at ${hex}: file .*ovldbreak\\.cc, line \[0-9\]+\\.\r\nwarning: Multiple breakpoints were set\\.\r\nUse the \"delete\" command to delete unwanted breakpoints\\."
+ "Breakpoint \[0-9\]+ at ${hex}: foo::foofunc. .2 locations..*"
# That's all, folks.
diff --git a/gdb/testsuite/gdb.cp/ovsrch.exp b/gdb/testsuite/gdb.cp/ovsrch.exp
index b509a25..f6ad34b 100644
--- a/gdb/testsuite/gdb.cp/ovsrch.exp
+++ b/gdb/testsuite/gdb.cp/ovsrch.exp
@@ -49,7 +49,7 @@ proc test_class {class} {
# Test whether open parentheses are correctly identified as overload
# information or conditional.
- gdb_test "break ${class}::foo if (a == 3)" "Breakpoint (\[0-9\]).*"
+ gdb_test "break ${class}::hibob if (a_param == 3)" "Breakpoint (\[0-9\]).*"
}
if { [skip_cplus_tests] } { continue }
@@ -73,28 +73,28 @@ if {![runto_main]} {
}
# Break in A::stop_here and run tests.
-if {[gdb_breakpoint "stop_here"]} {
- pass "break stop_here"
+if {[gdb_breakpoint "A::stop_here"]} {
+ pass "break A::stop_here"
}
-if {[gdb_breakpoint "'stop_here'"]} {
- pass "break 'stop_here'"
+if {[gdb_breakpoint "'A::stop_here'"]} {
+ pass "break 'A::stop_here'"
}
gdb_continue_to_breakpoint "stop_here"
-test_class outer
+test_class A::outer
# Break in A::B::stop_here_too and run tests.
-if {[gdb_breakpoint "B::stop_here_too"]} {
- pass "break B::stop_here_too"
+if {[gdb_breakpoint "A::B::stop_here_too"]} {
+ pass "break A::B::stop_here_too"
}
-if {[gdb_breakpoint "'B::stop_here_too'"]} {
- pass "break 'B::stop_here_too'"
+if {[gdb_breakpoint "'A::B::stop_here_too'"]} {
+ pass "break 'A::B::stop_here_too'"
}
gdb_continue_to_breakpoint "stop_here_too"
-test_class inner
+test_class A::B::inner
gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.cp/ovsrch.h b/gdb/testsuite/gdb.cp/ovsrch.h
index b2e518d..983b51e 100644
--- a/gdb/testsuite/gdb.cp/ovsrch.h
+++ b/gdb/testsuite/gdb.cp/ovsrch.h
@@ -24,6 +24,8 @@ namespace A
void foo (int) const;
void foo (char *) const;
bool func (void) { return true; }
+ void hibob (int) const;
+ void hibob (char *) const;
};
namespace B
@@ -34,6 +36,8 @@ namespace A
void foo (void) const;
void foo (int) const;
void foo (char *) const;
+ void hibob (int) const;
+ void hibob (char *) const;
};
}
}
diff --git a/gdb/testsuite/gdb.cp/ovsrch3.cc b/gdb/testsuite/gdb.cp/ovsrch3.cc
index e6e38a4..a7d9551 100644
--- a/gdb/testsuite/gdb.cp/ovsrch3.cc
+++ b/gdb/testsuite/gdb.cp/ovsrch3.cc
@@ -18,11 +18,21 @@
#include "ovsrch.h"
void
-A::outer::foo (int a) const
+A::outer::foo (int a_param) const
{
}
void
-A::B::inner::foo (int a) const
+A::B::inner::foo (int a_param) const
+{
+}
+
+void
+A::outer::hibob (int a_param) const
+{
+}
+
+void
+A::B::inner::hibob (int a_param) const
{
}
diff --git a/gdb/testsuite/gdb.cp/ovsrch4.cc b/gdb/testsuite/gdb.cp/ovsrch4.cc
index 2f0c1a6..5bb08b3 100644
--- a/gdb/testsuite/gdb.cp/ovsrch4.cc
+++ b/gdb/testsuite/gdb.cp/ovsrch4.cc
@@ -18,11 +18,21 @@
#include "ovsrch.h"
void
-A::outer::foo (char *a) const
+A::outer::foo (char *a_param) const
{
}
void
-A::B::inner::foo (char *a) const
+A::B::inner::foo (char *a_param) const
+{
+}
+
+void
+A::outer::hibob (char *a_param) const
+{
+}
+
+void
+A::B::inner::hibob (char *a_param) const
{
}
diff --git a/gdb/testsuite/gdb.cp/re-set-overloaded.exp b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
index 2052552..bd5f3ba 100644
--- a/gdb/testsuite/gdb.cp/re-set-overloaded.exp
+++ b/gdb/testsuite/gdb.cp/re-set-overloaded.exp
@@ -46,7 +46,6 @@ gdb_test_no_output {set variable $brk = $bpnum}
# runto or runto_main would call delete_breakpoints.
gdb_breakpoint "main"
gdb_run_cmd
-setup_kfail breakpoints/11657 *-*-*
gdb_test "" ".*" "start"
set test "breakpoint resolved"
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 6612b4a..8a68f25 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -109,12 +109,7 @@ proc test_template_breakpoints {} {
global hp_aCC_compiler
gdb_test_multiple "break T5<int>::T5" "constructor breakpoint" {
- -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2. T5<int>::T5\\(int\\) at .*\[\r\n\]*.3. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*\[\r\n\]*> $" {
- gdb_test "0" \
- "canceled" \
- "constructor breakpoint (obsolete format!)"
- }
- -re ".0. cancel\[\r\n\]*.1. all\[\r\n\]*.2. T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\) at .*templates.cc:.*\[\r\n\]*.3. T5<int>::T5\\(int\\) at .*templates.cc:.*\[\r\n\]*> $" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:T5<int>::T5\\((T5<int> const|const T5<int>) ?&\\)\[\r\n\]*.3.*templates.cc:T5<int>::T5\\(int\\)\[\r\n\]*> $" {
gdb_test "0" \
"canceled" \
"constructor breakpoint"
@@ -152,9 +147,26 @@ proc test_template_breakpoints {} {
set bp_location [gdb_get_line_number \
"set breakpoint on a line with no real code"]
- gdb_test "break ${testfile}.cc:${bp_location}" \
- "Breakpoint.*at.* file .*${testfile}.cc, line.*(2 locations).*" \
- "breakpoint on a line with no real code"
+
+ gdb_test_multiple "break ${testfile}.cc:${bp_location}" \
+ "breakpoint on a line with no real code" {
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*templates.cc:GetMax<int>\\(int, int\\)\[\r\n\]*.3.*templates.cc:GetMax<long>\\(long, long\\)\[\r\n\]*> $" {
+ gdb_test "0" \
+ "canceled" \
+ "breakpoint on a line with no real code"
+ }
+ -re "0. cancel.*\[\r\n\]*.1. all.*\[\r\n\]*.2.*\[\r\n\]*.3.*\[\r\n\]*> $" {
+ gdb_test "0" \
+ "nonsense intended to insure that this test fails" \
+ "breakpoint on a line with no real code"
+ }
+ -re ".*\n> $" {
+ gdb_test "0" \
+ "nonsense intended to insure that this test fails" \
+ "breakpoint on a line with no real code"
+ }
+ }
+
delete_breakpoints
}
@@ -168,7 +180,7 @@ proc test_template_calls {} {
if [target_info exists gdb,cannot_call_functions] {
setup_xfail "*-*-*" 2416
- fail "This target can not call functions"
+fail "This target can not call functions"
return
}
diff --git a/gdb/testsuite/gdb.linespec/Makefile.in b/gdb/testsuite/gdb.linespec/Makefile.in
new file mode 100644
index 0000000..2658a24
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/Makefile.in
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = lspec
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log gdb.log gdb.sum
diff --git a/gdb/testsuite/gdb.linespec/base/one/thefile.cc b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
new file mode 100644
index 0000000..f8712c2
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/one/thefile.cc
@@ -0,0 +1,20 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#define WANT_F1
+#include "../../lspec.h"
+
+
+
+
+
+
+int m(int x)
+{
+ return x + 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(int x)
+{
+ return x + 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/base/two/thefile.cc b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
new file mode 100644
index 0000000..ffca87a
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/base/two/thefile.cc
@@ -0,0 +1,20 @@
+/* The commented line must have the same line number in the other
+ "thefile.c". */
+
+#define WANT_F2
+#include "../../lspec.h"
+
+static int dupname(int y)
+{
+ label: return y;
+}
+
+int n(int y)
+{
+ return dupname(y) - 23; /* thefile breakpoint */
+}
+
+int NameSpace::overload(double x)
+{
+ return (int) x - 23;
+}
diff --git a/gdb/testsuite/gdb.linespec/body.h b/gdb/testsuite/gdb.linespec/body.h
new file mode 100644
index 0000000..e8765f6
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/body.h
@@ -0,0 +1,5 @@
+/* This is included directly into the body of a function. */
+
+/* body breakpoint no code */
+
+return x;
diff --git a/gdb/testsuite/gdb.linespec/linespec.exp b/gdb/testsuite/gdb.linespec/linespec.exp
new file mode 100644
index 0000000..440233a
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/linespec.exp
@@ -0,0 +1,117 @@
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Tests of ambiguous linespecs.
+
+set testfile linespec
+
+set exefile lspec
+set binfile ${objdir}/${subdir}/${exefile}
+
+set baseone base/one/thefile.cc
+set basetwo base/two/thefile.cc
+
+if {[skip_cplus_tests]} {
+ unsupported linespec.exp
+ return
+}
+
+if {[prepare_for_testing ${testfile}.exp $exefile \
+ [list lspec.cc $baseone $basetwo] \
+ {debug nowarnings}]} {
+ return -1
+}
+
+gdb_test_no_output "set multiple-symbols all" \
+ "set multiple-symbols to all for linespec tests"
+
+set l1 [gdb_get_line_number "thefile breakpoint" $baseone]
+set l2 [gdb_get_line_number "thefile breakpoint" $basetwo]
+
+if {$l1 != $l2} {
+ error "somebody incompatibly modified the source files needed by linespec.exp"
+}
+
+gdb_test "break thefile.cc:$l1" \
+ "Breakpoint 1 at $hex: thefile.cc:$l1. \[(\]2 locations\[)\]" \
+ "multi-location break using file:line"
+
+# We'd like this to work, but it currently does not.
+# gdb_test "break one/thefile.cc:$l1"
+
+gdb_test "break dupname" \
+ "Breakpoint 2 at $hex: dupname. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name"
+
+gdb_test "break dupname:label" \
+ "Breakpoint 3 at $hex: dupname:label. \[(\]2 locations\[)\]" \
+ "multi-location break using duplicate function name and label"
+
+gdb_test_no_output "set breakpoint pending off" \
+ "disable pending breakpoints for linespec tests"
+
+# This is PR breakpoints/12856.
+gdb_test "break lspec.cc:nosuchfunction" \
+ "Function \"nosuchfunction\" not defined in \"lspec.cc\"." \
+ "set breakpoint on non-existent function"
+
+gdb_test "break NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: NameSpace::overload. \[(\]3 locations\[)\]" \
+ "set breakpoint at all instances of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at lspec.cc instance of NameSpace::overload"
+
+gdb_test "break lspec.cc:NameSpace::overload(double)" \
+ "Function \"NameSpace::overload\\(double\\)\" not defined in \"lspec.cc\"." \
+ "set breakpoint at non-existent lspec.cc instance of NameSpace::overload"
+
+gdb_test "break NameSpace::overload()" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.cc, line 7." \
+ "set breakpoint at specific instance of NameSpace::overload"
+
+# This should manage to set a breakpoint even though body.h does not
+# include all of the function in question.
+set line [gdb_get_line_number "body breakpoint no code" body.h]
+gdb_test "break body.h:$line" \
+ "Breakpoint \[0-9\]+.*" \
+ "set breakpoint in body.h"
+
+# This should only have a single location -- in f1.
+set line [gdb_get_line_number "f1 breakpoint" lspec.h]
+gdb_test "break lspec.h:$line" \
+ "Breakpoint \[0-9\]+ at $hex: file .*lspec.h, line $line." \
+ "set breakpoint in f1"
+
+#
+# Multi-inferior tests.
+#
+
+gdb_test "add-inferior" "Added inferior 2" \
+ "add inferior for linespec tests"
+
+gdb_test "inferior 2" "Switching to inferior 2 .*" \
+ "switch to inferior 2 for linespec tests"
+
+# Note that in particular this should not cause errors when re-setting
+# breakpoints.
+gdb_test "file $binfile" \
+ "Reading symbols from .*done." \
+ "set the new inferior file for linespec tests"
+
+gdb_test "break main" \
+ "Breakpoint \[0-9\]+ at $hex: main. .2 locations." \
+ "set breakpoint at main in both inferiors"
diff --git a/gdb/testsuite/gdb.linespec/lspec.cc b/gdb/testsuite/gdb.linespec/lspec.cc
new file mode 100644
index 0000000..b1092e2
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.cc
@@ -0,0 +1,19 @@
+#include "lspec.h"
+
+static int dupname (int x) { label: return x; }
+
+int NameSpace::overload()
+{
+ return 23;
+}
+
+int body_elsewhere()
+{
+ int x = 5;
+#include "body.h"
+}
+
+int main()
+{
+ return dupname(0) + m(0) + n(0) + f1() + f2() + body_elsewhere();
+}
diff --git a/gdb/testsuite/gdb.linespec/lspec.h b/gdb/testsuite/gdb.linespec/lspec.h
new file mode 100644
index 0000000..0a647fa
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/lspec.h
@@ -0,0 +1,26 @@
+extern int m(int x);
+extern int n(int y);
+
+namespace NameSpace {
+ int overload ();
+ int overload (int);
+ int overload (double);
+};
+
+#ifdef WANT_F1
+int f1(void)
+{
+ return 1; /* f1 breakpoint */
+}
+#else
+extern int f1(void);
+#endif
+
+#ifdef WANT_F2
+int f2(void)
+{
+ return 1; /* f2 breakpoint */
+}
+#else
+extern int f2(void);
+#endif
diff --git a/gdb/testsuite/gdb.objc/objcdecode.exp b/gdb/testsuite/gdb.objc/objcdecode.exp
index 720bfd8..e3916f6 100644
--- a/gdb/testsuite/gdb.objc/objcdecode.exp
+++ b/gdb/testsuite/gdb.objc/objcdecode.exp
@@ -52,17 +52,19 @@ proc do_objc_tests {} {
do_objc_tests
+gdb_test_no_output "set multiple-symbols ask"
+
#
# Break on multiply defined method (PR objc/1236)
#
set name "break on multiply defined method"
gdb_test_multiple "break multipleDef" $name \
{
- -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] -.Decode multipleDef. at .*\r\n\\\[3\\\] multipleDef at .*\r\n> $" {
+ -re "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] .*${srcfile}:-.Decode multipleDef.\r\n\\\[3\\\] .*${srcfile}:multipleDef\r\n> $" {
send_gdb "3\n"
exp_continue
}
- -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: file .*\r\n$gdb_prompt $" { pass $name }
+ -re "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+: .*\r\n$gdb_prompt $" { pass $name }
-re ".*$gdb_prompt $" { kfail "gdb/1236" $name }
}
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 679cc32..89a2e24 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -74,6 +74,7 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline2" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
+gdb_test_no_output "set breakpoint pending off"
gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
@@ -81,7 +82,6 @@ gdb_test "info trace" "No tracepoints.*" \
# 1.3 trace line in invalid source file
gdb_delete_tracepoints
-gdb_test_no_output "set breakpoint pending off"
gdb_test "trace NoSuChFiLe.c:1" "No source file named NoSuChFiLe.c." \
"1.3a: trace invalid source file"
gdb_test "info trace" "No tracepoints.*" \
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 97ab633..824024a 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2493,7 +2493,7 @@ scope_info (char *args, int from_tty)
error (_("requires an argument (function, "
"line or *addr) to define a scope"));
- sals = decode_line_1 (&args, 1, NULL, 0, NULL);
+ sals = decode_line_1 (&args, 1, NULL, 0);
if (sals.nelts == 0)
return; /* Presumably decode_line_1 has already warned. */
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 4c8658d..9b936e1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -455,29 +455,34 @@ tui_update_breakpoint_info (struct tui_win_info *win,
bp != (struct breakpoint *) NULL;
bp = bp->next)
{
+ struct bp_location *loc;
+
gdb_assert (line->line_or_addr.loa == LOA_LINE
|| line->line_or_addr.loa == LOA_ADDRESS);
- if ((win == TUI_SRC_WIN
- && bp->source_file
- && (filename_cmp (src->filename, bp->source_file) == 0)
- && line->line_or_addr.loa == LOA_LINE
- && bp->line_number == line->line_or_addr.u.line_no)
- || (win == TUI_DISASM_WIN
- && line->line_or_addr.loa == LOA_ADDRESS
- && bp->loc != NULL
- && bp->loc->address == line->line_or_addr.u.addr))
- {
- if (bp->enable_state == bp_disabled)
- mode |= TUI_BP_DISABLED;
- else
- mode |= TUI_BP_ENABLED;
- if (bp->hit_count)
- mode |= TUI_BP_HIT;
- if (bp->loc->cond)
- mode |= TUI_BP_CONDITIONAL;
- if (bp->type == bp_hardware_breakpoint)
- mode |= TUI_BP_HARDWARE;
- }
+
+ for (loc = bp->loc; loc != NULL; loc = loc->next)
+ {
+ if ((win == TUI_SRC_WIN
+ && loc->source_file
+ && (filename_cmp (src->filename, loc->source_file) == 0)
+ && line->line_or_addr.loa == LOA_LINE
+ && loc->line_number == line->line_or_addr.u.line_no)
+ || (win == TUI_DISASM_WIN
+ && line->line_or_addr.loa == LOA_ADDRESS
+ && loc->address == line->line_or_addr.u.addr))
+ {
+ if (bp->enable_state == bp_disabled)
+ mode |= TUI_BP_DISABLED;
+ else
+ mode |= TUI_BP_ENABLED;
+ if (bp->hit_count)
+ mode |= TUI_BP_HIT;
+ if (bp->loc->cond)
+ mode |= TUI_BP_CONDITIONAL;
+ if (bp->type == bp_hardware_breakpoint)
+ mode |= TUI_BP_HARDWARE;
+ }
+ }
}
if (line->has_break != mode)
{
diff --git a/gdb/utils.c b/gdb/utils.c
index a43b13d..cc93915 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -3651,6 +3651,17 @@ compare_positive_ints (const void *ap, const void *bp)
return * (int *) ap - * (int *) bp;
}
+/* String compare function for qsort. */
+
+int
+compare_strings (const void *arg1, const void *arg2)
+{
+ const char **s1 = (const char **) arg1;
+ const char **s2 = (const char **) arg2;
+
+ return strcmp (*s1, *s2);
+}
+
#define AMBIGUOUS_MESS1 ".\nMatching formats:"
#define AMBIGUOUS_MESS2 \
".\nUse \"set gnutarget format-name\" to specify the format."
^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2011-11-23 21:33 UTC | newest]
Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-28 17:34 RFA: implement ambiguous linespec proposal Tom Tromey
2011-10-28 20:52 ` Matt Rice
2011-11-01 20:38 ` Tom Tromey
2011-10-28 22:41 ` Jan Kratochvil
2011-11-01 20:58 ` Tom Tromey
2011-11-03 20:49 ` Tom Tromey
2011-11-04 7:46 ` Jan Kratochvil
2011-11-08 16:36 ` Tom Tromey
2011-11-09 16:05 ` Joel Brobecker
2011-11-09 17:12 ` Tom Tromey
2011-11-09 17:56 ` Joel Brobecker
2011-11-09 18:19 ` Tom Tromey
2011-11-09 19:00 ` Joel Brobecker
2011-11-14 21:04 ` Tom Tromey
2011-11-14 21:32 ` Jerome Guitton
2011-11-09 18:37 ` Tom Tromey
2011-11-14 21:11 ` Tom Tromey
2011-11-15 16:30 ` Tom Tromey
2011-11-15 16:59 ` Pierre Muller
2011-11-16 0:09 ` Jan Kratochvil
2011-11-16 1:58 ` Joel Brobecker
2011-11-16 14:46 ` Tom Tromey
2011-11-18 14:10 ` Tom Tromey
2011-11-16 21:23 ` Stan Shebs
2011-11-16 2:28 ` Yao Qi
2011-11-16 3:20 ` Doug Evans
2011-11-16 14:46 ` Tom Tromey
2011-11-16 16:06 ` Tom Tromey
2011-11-16 4:57 ` Doug Evans
2011-11-16 5:22 ` Doug Evans
2011-11-16 14:54 ` Tom Tromey
2011-11-16 16:32 ` Doug Evans
2011-11-16 16:39 ` Tom Tromey
2011-11-16 14:49 ` Tom Tromey
2011-11-16 8:15 ` Yao Qi
2011-11-16 16:17 ` Tom Tromey
2011-11-16 15:43 ` Yao Qi
2011-11-16 16:11 ` Tom Tromey
2011-11-16 16:44 ` Tom Tromey
2011-11-17 3:49 ` Yao Qi
2011-11-21 21:50 ` Tom Tromey
2011-11-23 21:33 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox