diff options
author | Pedro Alves <palves@redhat.com> | 2017-11-29 19:33:23 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2017-11-29 19:43:48 +0000 |
commit | a20714ff39f621961151d0c204e89062ab2107eb (patch) | |
tree | 6a04775e3cd8c3f617986bb98abc2d3df77f54df /gdb/linespec.c | |
parent | a207cff2da9f154e4f581b19dcde215593bfccf9 (diff) | |
download | fsf-binutils-gdb-a20714ff39f621961151d0c204e89062ab2107eb.zip fsf-binutils-gdb-a20714ff39f621961151d0c204e89062ab2107eb.tar.gz fsf-binutils-gdb-a20714ff39f621961151d0c204e89062ab2107eb.tar.bz2 |
Make "break foo" find "A::foo", A::B::foo", etc. [C++ and wild matching]
This patch teaches GDB about setting breakpoints in all scopes
(namespaces and classes) by default.
Here's a contrived example:
(gdb) b func<tab>
(anonymous namespace)::A::function() Bn::(anonymous namespace)::B::function() function(int, int)
(anonymous namespace)::B::function() Bn::(anonymous namespace)::function() gdb::(anonymous namespace)::A::function()
(anonymous namespace)::B::function() const Bn::(anonymous namespace)::function(int, int) gdb::(anonymous namespace)::function()
(anonymous namespace)::function() Bn::B::func() gdb::(anonymous namespace)::function(int, int)
(anonymous namespace)::function(int, int) Bn::B::function() gdb::A::func()
A::func() Bn::func() gdb::A::function()
A::function() Bn::function() gdb::func()
B::func() Bn::function(int, int) gdb::function()
B::function() Bn::function(long) gdb::function(int, int)
B::function() const func() gdb::function(long)
B::function_const() const function()
(gdb) b function
Breakpoint 1 at 0x4005ce: function. (26 locations)
(gdb) b B::function<tab>
(anonymous namespace)::B::function() B::function() const Bn::B::function()
(anonymous namespace)::B::function() const B::function_const() const
B::function() Bn::(anonymous namespace)::B::function()
(gdb) b B::function
Breakpoint 1 at 0x40072c: B::function. (6 locations)
To get back the original behavior of interpreting the function name as
a fully-qualified name, you can use the new "-qualified" (or "-q")
option/flag (added by this commit). For example:
(gdb) b B::function
(anonymous namespace)::B::function() B::function() const Bn::B::function()
(anonymous namespace)::B::function() const B::function_const() const
B::function() Bn::(anonymous namespace)::B::function()
vs:
(gdb) b -qualified B::function
B::function() B::function() const B::function_const() const
I've chosen "-qualified" / "-q" because "-f" (for "full" or
"fully-qualified") is already taken for "-function".
Note: the "-qualified" option works with both linespecs and explicit
locations. I.e., these are equivalent:
(gdb) b -q func
(gdb) b -q -f func
and so are these:
(gdb) b -q filename.cc:func
(gdb) b -q -s filename.cc -f func
(gdb) b -s filename.cc -q -f func
(gdb) b -s filename.cc -f func -q
To better understand why I consider wild matching the better default,
consider what happens when we get to the point when _all_ of GDB is
wrapped under "namespace gdb {}". I have a patch series that does
that, and when I started debugging that GDB, I immediately became
frustrated. You'd have to write "b gdb::internal_error", "b
gdb::foo", "b gdb::bar", etc. etc., which gets annoying pretty
quickly. OTOH, consider how this makes it very easy to set
breakpoints in classes wrapped in anonymous namespaces. You just
don't think of them, GDB finds the symbols for you automatically.
(At the Cauldron a couple months ago, several people told me that they
run into a similar issue when debugging other C++ projects. One
example was when debugging LLVM, which puts all its code under the
"llvm" namespace.)
Implementation-wise, what the patch does is:
- makes C++ symbol name hashing only consider the last component of
a symbol name. (so that we can look up symbol names by
last-component name only).
- adds a C++ symbol name matcher for symbol_name_match_type::WILD,
which ignores missing leading specifiers / components.
- adjusts a few preexisting testsuite tests to use "-qualified" when
they mean it.
- adds new testsuite tests.
- adds unit tests.
Grows the gdb.linespec/ tests like this:
-# of expected passes 7823
+# of expected passes 8977
gdb/ChangeLog:
2017-11-29 Pedro Alves <palves@redhat.com>
* NEWS: Mention that breakpoints on C++ functions are now set on
on all namespaces/classes by default, and mention "break
-qualified".
* ax-gdb.c (agent_command_1): Adjust to pass a
symbol_name_match_type to new_linespec_location.
* breakpoint.c (parse_breakpoint_sals): Adjust to
get_linespec_location's return type change.
(strace_marker_create_sals_from_location): Adjust to pass a
symbol_name_match_type to new_linespec_location.
(strace_marker_decode_location): Adjust to get_linespec_location's
return type change.
(strace_command): Adjust to pass a symbol_name_match_type to
new_linespec_location.
(LOCATION_HELP_STRING): Add paragraph about wildmatching, and
mention "-qualified".
* c-lang.c (cplus_language_defn): Install cp_search_name_hash.
* completer.c (explicit_location_match_type::MATCH_QUALIFIED): New
enumerator.
(complete_address_and_linespec_locations): New parameter
'match_type'. Pass it down.
(explicit_options): Add "-qualified".
(collect_explicit_location_matches): Pass the requested match type
to the linespec completers. Handle MATCH_QUALIFIED.
(location_completer): Handle "-qualified" combined with linespecs.
* cp-support.c (cp_search_name_hash): New.
(cp_symbol_name_matches_1): Implement wild matching for C++.
(cp_fq_symbol_name_matches): Reimplement.
(cp_get_symbol_name_matcher): Return different matchers depending
on the lookup name's match type.
(selftests::test_cp_symbol_name_matches): Add wild matching tests.
* cp-support.h (cp_search_name_hash): New declaration.
* dwarf2read.c
(selftests::dw2_expand_symtabs_matching::test_symbols): Add
symbols.
(test_dw2_expand_symtabs_matching_symbol): Add wild matching
tests.
* guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Adjust to
pass a symbol_name_match_type to new_linespec_location.
* linespec.c (linespec_parse_basic): Lookup function symbols using
the parser's symbol name match type.
(convert_explicit_location_to_linespec): New
symbol_name_match_type parameter. Pass it down to
find_linespec_symbols.
(convert_explicit_location_to_sals): Pass the location's name
match type to convert_explicit_location_to_linespec.
(parse_linespec): New match_type parameter. Save it in the
parser.
(linespec_parser_new): Default to symbol_name_match_type::WILD.
(linespec_complete_function): New symbol_name_match_type
parameter. Use it.
(complete_linespec_component): Pass down the parser's recorded
name match type.
(linespec_complete_label): New symbol_name_match_type parameter.
Use it.
(linespec_complete): New symbol_name_match_type parameter. Save
it in the parser and pass it down. Adjust to
get_linespec_location's prototype change.
(find_function_symbols, find_linespec_symbols): New
symbol_name_match_type parameter. Pass it down instead of
assuming symbol_name_match_type::WILD.
* linespec.h (linespec_complete, linespec_complete_function)
(linespec_complete_label): New symbol_name_match_type parameter.
* location.c (event_location::linespec_location): Now a struct
linespec_location.
(EL_LINESPEC): Adjust.
(initialize_explicit_location): Default to
symbol_name_match_type::WILD.
(new_linespec_location): New symbol_name_match_type parameter.
Record it in the location.
(get_linespec_location): Now returns a struct linespec_location.
(new_explicit_location): Also copy func_name_match_type.
(explicit_to_string_internal)
(string_to_explicit_location): Handle "-qualified".
(copy_event_location): Adjust to LINESPEC_LOCATION type change.
Copy symbol_name_match_type fields.
(event_location_deleter::operator()): Adjust to LINESPEC_LOCATION
type change.
(event_location_to_string): Adjust to LINESPEC_LOCATION type
change. Handle "-qualfied".
(string_to_explicit_location): Handle "-qualified".
(string_to_event_location_basic): New symbol_name_match_type
parameter. Pass it down.
(string_to_event_location): Handle "-qualified".
* location.h (struct linespec_location): New.
(explicit_location::func_name_match_type): New field.
(new_linespec_location): Now returns a const linespec_location *.
(string_to_event_location_basic): New symbol_name_match_type
parameter.
(explicit_completion_info::saw_explicit_location_option): New
field.
* mi/mi-cmd-break.c (mi_cmd_break_insert_1): Adjust to pass a
symbol_name_match_type to new_linespec_location.
* python/py-breakpoint.c (bppy_init): Likewise.
* python/python.c (gdbpy_decode_line): Likewise.
gdb/testsuite/ChangeLog:
2017-11-29 Pedro Alves <palves@redhat.com>
* gdb.base/langs.exp: Use -qualified.
* gdb.cp/meth-typedefs.exp: Use -qualified, and add tests without
it.
* gdb.cp/namespace.exp: Use -qualified.
* gdb.linespec/cpcompletion.exp (overload-2, fqn, fqn-2)
(overload-3, template-overload, template-ret-type, const-overload)
(const-overload-quoted, anon-ns, ambiguous-prefix): New
procedures.
(test_driver): Call them.
* gdb.cp/save-bp-qualified.cc: New.
* gdb.cp/save-bp-qualified.exp: New.
* gdb.linespec/explicit.exp: Test -qualified.
* lib/completion-support.exp (completion::explicit_opts_list): Add
"-qualified".
* lib/gdb.exp (gdb_breakpoint): Handle "qualified".
gdb/doc/ChangeLog:
2017-11-29 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Linespec Locations): Document how "function" is
interpreted in C++ and Ada. Document "-qualified".
(Explicit Locations): Document how "-function" is interpreted in
C++ and Ada. Document "-qualified".
Diffstat (limited to 'gdb/linespec.c')
-rw-r--r-- | gdb/linespec.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/gdb/linespec.c b/gdb/linespec.c index f1e1ea9..909dc32 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -359,6 +359,7 @@ static VEC (symbolp) *find_label_symbols (struct linespec_state *self, static void find_linespec_symbols (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs, const char *name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms); @@ -1865,9 +1866,12 @@ linespec_parse_basic (linespec_parser *parser) completion_tracker tmp_tracker; const char *source_filename = PARSER_EXPLICIT (parser)->source_filename; + symbol_name_match_type match_type + = PARSER_EXPLICIT (parser)->func_name_match_type; linespec_complete_function (tmp_tracker, parser->completion_word, + match_type, source_filename); if (tmp_tracker.have_completions ()) @@ -1892,6 +1896,7 @@ linespec_parse_basic (linespec_parser *parser) /* Try looking it up as a function/method. */ find_linespec_symbols (PARSER_STATE (parser), PARSER_RESULT (parser)->file_symtabs, name, + PARSER_EXPLICIT (parser)->func_name_match_type, &symbols, &minimal_symbols); if (symbols != NULL || minimal_symbols != NULL) @@ -2383,12 +2388,15 @@ convert_explicit_location_to_linespec (struct linespec_state *self, linespec_p result, const char *source_filename, const char *function_name, + symbol_name_match_type fname_match_type, const char *label_name, struct line_offset line_offset) { VEC (symbolp) *symbols, *labels; VEC (bound_minimal_symbol_d) *minimal_symbols; + result->explicit_loc.func_name_match_type = fname_match_type; + if (source_filename != NULL) { TRY @@ -2412,8 +2420,8 @@ convert_explicit_location_to_linespec (struct linespec_state *self, if (function_name != NULL) { find_linespec_symbols (self, result->file_symtabs, - function_name, &symbols, - &minimal_symbols); + function_name, fname_match_type, + &symbols, &minimal_symbols); if (symbols == NULL && minimal_symbols == NULL) symbol_not_found_error (function_name, @@ -2453,6 +2461,7 @@ convert_explicit_location_to_sals (struct linespec_state *self, convert_explicit_location_to_linespec (self, result, explicit_loc->source_filename, explicit_loc->function_name, + explicit_loc->func_name_match_type, explicit_loc->label_name, explicit_loc->line_offset); return convert_linespec_to_sals (self, result); @@ -2506,10 +2515,12 @@ convert_explicit_location_to_sals (struct linespec_state *self, if no file is validly specified. Callers must check that. Also, the line number returned may be invalid. */ -/* Parse the linespec in ARG. */ +/* Parse the linespec in ARG. MATCH_TYPE indicates how function names + should be matched. */ static std::vector<symtab_and_line> -parse_linespec (linespec_parser *parser, const char *arg) +parse_linespec (linespec_parser *parser, const char *arg, + symbol_name_match_type match_type) { linespec_token token; struct gdb_exception file_exception = exception_none; @@ -2539,6 +2550,7 @@ parse_linespec (linespec_parser *parser, const char *arg) parser->lexer.stream = arg; parser->completion_word = arg; parser->complete_what = linespec_complete_what::FUNCTION; + PARSER_EXPLICIT (parser)->func_name_match_type = match_type; /* Initialize the default symtab and line offset. */ initialize_defaults (&PARSER_STATE (parser)->default_symtab, @@ -2747,6 +2759,8 @@ linespec_parser_new (linespec_parser *parser, memset (parser, 0, sizeof (linespec_parser)); parser->lexer.current.type = LSTOKEN_CONSUMED; memset (PARSER_RESULT (parser), 0, sizeof (struct linespec)); + PARSER_EXPLICIT (parser)->func_name_match_type + = symbol_name_match_type::WILD; PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN; linespec_state_constructor (PARSER_STATE (parser), flags, language, search_pspace, @@ -2828,10 +2842,10 @@ linespec_lex_to_end (const char **stringp) void linespec_complete_function (completion_tracker &tracker, const char *function, + symbol_name_match_type func_match_type, const char *source_filename) { complete_symbol_mode mode = complete_symbol_mode::LINESPEC; - symbol_name_match_type func_match_type = symbol_name_match_type::WILD; if (source_filename != NULL) { @@ -2870,7 +2884,9 @@ complete_linespec_component (linespec_parser *parser, { completion_list fn_list; - linespec_complete_function (tracker, text, source_filename); + symbol_name_match_type match_type + = PARSER_EXPLICIT (parser)->func_name_match_type; + linespec_complete_function (tracker, text, match_type, source_filename); if (source_filename == NULL) { /* Haven't seen a source component, like in "b @@ -2940,6 +2956,7 @@ linespec_complete_label (completion_tracker &tracker, const struct language_defn *language, const char *source_filename, const char *function_name, + symbol_name_match_type func_name_match_type, const char *label_name) { linespec_parser parser; @@ -2956,6 +2973,7 @@ linespec_complete_label (completion_tracker &tracker, PARSER_RESULT (&parser), source_filename, function_name, + func_name_match_type, NULL, unknown_offset); } CATCH (ex, RETURN_MASK_ERROR) @@ -2973,7 +2991,8 @@ linespec_complete_label (completion_tracker &tracker, /* See description in linespec.h. */ void -linespec_complete (completion_tracker &tracker, const char *text) +linespec_complete (completion_tracker &tracker, const char *text, + symbol_name_match_type match_type) { linespec_parser parser; struct cleanup *cleanup; @@ -2982,6 +3001,7 @@ linespec_complete (completion_tracker &tracker, const char *text) linespec_parser_new (&parser, 0, current_language, NULL, NULL, 0, NULL); cleanup = make_cleanup (linespec_parser_delete, &parser); parser.lexer.saved_arg = text; + PARSER_EXPLICIT (&parser)->func_name_match_type = match_type; PARSER_STREAM (&parser) = text; parser.completion_tracker = &tracker; @@ -2991,7 +3011,7 @@ linespec_complete (completion_tracker &tracker, const char *text) furthest completion point we managed to parse to. */ TRY { - parse_linespec (&parser, text); + parse_linespec (&parser, text, match_type); } CATCH (except, RETURN_MASK_ERROR) { @@ -3039,7 +3059,7 @@ linespec_complete (completion_tracker &tracker, const char *text) VEC (bound_minimal_symbol_d) *minimal_symbols; find_linespec_symbols (PARSER_STATE (&parser), PARSER_RESULT (&parser)->file_symtabs, - func_name, + func_name, match_type, &function_symbols, &minimal_symbols); PARSER_RESULT (&parser)->function_symbols = function_symbols; @@ -3181,7 +3201,9 @@ event_location_to_sals (linespec_parser *parser, PARSER_STATE (parser)->is_linespec = 1; TRY { - result = parse_linespec (parser, get_linespec_location (location)); + const linespec_location *ls = get_linespec_location (location); + result = parse_linespec (parser, + ls->spec_string, ls->match_type); } CATCH (except, RETURN_MASK_ERROR) { @@ -3492,7 +3514,8 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg) else str = saved_arg; - self->canonical->location = new_linespec_location (&str); + self->canonical->location + = new_linespec_location (&str, symbol_name_match_type::FULL); } } @@ -3936,6 +3959,7 @@ symtabs_from_filename (const char *filename, static void find_function_symbols (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, const char *name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms) { @@ -3955,8 +3979,7 @@ find_function_symbols (struct linespec_state *state, add_all_symbol_names_from_pspace (&info, state->search_pspace, symbol_names, FUNCTIONS_DOMAIN); else - add_matching_symbols_to_info (name, symbol_name_match_type::WILD, - FUNCTIONS_DOMAIN, + add_matching_symbols_to_info (name, name_match_type, FUNCTIONS_DOMAIN, &info, state->search_pspace); do_cleanups (cleanup); @@ -3985,6 +4008,7 @@ static void find_linespec_symbols (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs, const char *lookup_name, + symbol_name_match_type name_match_type, VEC (symbolp) **symbols, VEC (bound_minimal_symbol_d) **minsyms) { @@ -4002,6 +4026,7 @@ find_linespec_symbols (struct linespec_state *state, 2) break class::method where method is in class (and not a baseclass) */ find_function_symbols (state, file_symtabs, lookup_name, + name_match_type, symbols, minsyms); /* If we were unable to locate a symbol of the same name, try dividing |