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".
This commit is contained in:
Pedro Alves 2017-11-29 19:33:23 +00:00
parent a207cff2da
commit a20714ff39
29 changed files with 1233 additions and 125 deletions

View file

@ -41,13 +41,14 @@ struct event_location
union
{
/* A generic "this is a string specification" for a location.
This representation is used by both "normal" linespecs and
probes. */
/* A probe. */
char *addr_string;
#define EL_LINESPEC(P) ((P)->u.addr_string)
#define EL_PROBE(P) ((P)->u.addr_string)
/* A "normal" linespec. */
struct linespec_location linespec_location;
#define EL_LINESPEC(P) (&(P)->u.linespec_location)
/* An address in the inferior. */
CORE_ADDR address;
#define EL_ADDRESS(P) (P)->u.address
@ -78,17 +79,20 @@ initialize_explicit_location (struct explicit_location *explicit_loc)
{
memset (explicit_loc, 0, sizeof (struct explicit_location));
explicit_loc->line_offset.sign = LINE_OFFSET_UNKNOWN;
explicit_loc->func_name_match_type = symbol_name_match_type::WILD;
}
/* See description in location.h. */
event_location_up
new_linespec_location (const char **linespec)
new_linespec_location (const char **linespec,
symbol_name_match_type match_type)
{
struct event_location *location;
location = XCNEW (struct event_location);
EL_TYPE (location) = LINESPEC_LOCATION;
EL_LINESPEC (location)->match_type = match_type;
if (*linespec != NULL)
{
const char *p;
@ -97,14 +101,14 @@ new_linespec_location (const char **linespec)
linespec_lex_to_end (linespec);
p = remove_trailing_whitespace (orig, *linespec);
if ((p - orig) > 0)
EL_LINESPEC (location) = savestring (orig, p - orig);
EL_LINESPEC (location)->spec_string = savestring (orig, p - orig);
}
return event_location_up (location);
}
/* See description in location.h. */
const char *
const linespec_location *
get_linespec_location (const struct event_location *location)
{
gdb_assert (EL_TYPE (location) == LINESPEC_LOCATION);
@ -180,6 +184,9 @@ new_explicit_location (const struct explicit_location *explicit_loc)
initialize_explicit_location (EL_EXPLICIT (&tmp));
if (explicit_loc != NULL)
{
EL_EXPLICIT (&tmp)->func_name_match_type
= explicit_loc->func_name_match_type;
if (explicit_loc->source_filename != NULL)
{
EL_EXPLICIT (&tmp)->source_filename
@ -244,6 +251,8 @@ explicit_to_string_internal (int as_linespec,
{
if (need_space)
buf.putc (space);
if (explicit_loc->func_name_match_type == symbol_name_match_type::FULL)
buf.puts ("-qualified ");
if (!as_linespec)
buf.puts ("-function ");
buf.puts (explicit_loc->function_name);
@ -307,8 +316,10 @@ copy_event_location (const struct event_location *src)
switch (EL_TYPE (src))
{
case LINESPEC_LOCATION:
if (EL_LINESPEC (src) != NULL)
EL_LINESPEC (dst) = xstrdup (EL_LINESPEC (src));
EL_LINESPEC (dst)->match_type = EL_LINESPEC (src)->match_type;
if (EL_LINESPEC (src)->spec_string != NULL)
EL_LINESPEC (dst)->spec_string
= xstrdup (EL_LINESPEC (src)->spec_string);
break;
case ADDRESS_LOCATION:
@ -316,6 +327,8 @@ copy_event_location (const struct event_location *src)
break;
case EXPLICIT_LOCATION:
EL_EXPLICIT (dst)->func_name_match_type
= EL_EXPLICIT (src)->func_name_match_type;
if (EL_EXPLICIT (src)->source_filename != NULL)
EL_EXPLICIT (dst)->source_filename
= xstrdup (EL_EXPLICIT (src)->source_filename);
@ -353,7 +366,7 @@ event_location_deleter::operator() (event_location *location) const
switch (EL_TYPE (location))
{
case LINESPEC_LOCATION:
xfree (EL_LINESPEC (location));
xfree (EL_LINESPEC (location)->spec_string);
break;
case ADDRESS_LOCATION:
@ -388,8 +401,17 @@ event_location_to_string (struct event_location *location)
switch (EL_TYPE (location))
{
case LINESPEC_LOCATION:
if (EL_LINESPEC (location) != NULL)
EL_STRING (location) = xstrdup (EL_LINESPEC (location));
if (EL_LINESPEC (location)->spec_string != NULL)
{
linespec_location *ls = EL_LINESPEC (location);
if (ls->match_type == symbol_name_match_type::FULL)
{
EL_STRING (location)
= concat ("-qualified ", ls->spec_string, (char *) NULL);
}
else
EL_STRING (location) = xstrdup (ls->spec_string);
}
break;
case ADDRESS_LOCATION:
@ -756,12 +778,23 @@ string_to_explicit_location (const char **argp,
argument. */
bool have_oarg = false;
/* True if the option needs an argument. */
bool need_oarg = false;
/* Convenience to consistently set both OARG/HAVE_OARG from
ARG. */
auto set_oarg = [&] (gdb::unique_xmalloc_ptr<char> arg)
{
if (completion_info != NULL)
{
/* We do this here because the set of options that take
arguments matches the set of explicit location
options. */
completion_info->saw_explicit_location_option = true;
}
oarg = std::move (arg);
have_oarg = oarg != NULL;
need_oarg = true;
};
if (strncmp (opt.get (), "-source", len) == 0)
@ -776,6 +809,11 @@ string_to_explicit_location (const char **argp,
completion_info));
EL_EXPLICIT (location)->function_name = oarg.release ();
}
else if (strncmp (opt.get (), "-qualified", len) == 0)
{
EL_EXPLICIT (location)->func_name_match_type
= symbol_name_match_type::FULL;
}
else if (strncmp (opt.get (), "-line", len) == 0)
{
set_oarg (explicit_location_lex_one (argp, language, NULL));
@ -814,7 +852,7 @@ string_to_explicit_location (const char **argp,
case, it provides a much better user experience to issue
the "invalid argument" error before any missing
argument error. */
if (!have_oarg && completion_info == NULL)
if (need_oarg && !have_oarg && completion_info == NULL)
error (_("missing argument for \"%s\""), opt.get ());
}
@ -837,7 +875,8 @@ string_to_explicit_location (const char **argp,
event_location_up
string_to_event_location_basic (const char **stringp,
const struct language_defn *language)
const struct language_defn *language,
symbol_name_match_type match_type)
{
event_location_up location;
const char *cs;
@ -865,7 +904,7 @@ string_to_event_location_basic (const char **stringp,
else
{
/* Everything else is a linespec. */
location = new_linespec_location (stringp);
location = new_linespec_location (stringp, match_type);
}
}
@ -879,6 +918,7 @@ string_to_event_location (const char **stringp,
const struct language_defn *language)
{
const char *arg, *orig;
symbol_name_match_type match_type = symbol_name_match_type::WILD;
/* Try an explicit location. */
orig = arg = *stringp;
@ -888,15 +928,21 @@ string_to_event_location (const char **stringp,
/* It was a valid explicit location. Advance STRINGP to
the end of input. */
*stringp += arg - orig;
}
else
{
/* Everything else is a "basic" linespec, address, or probe
location. */
location = string_to_event_location_basic (stringp, language);
/* If the user really specified a location, then we're done. */
if (!event_location_empty_p (location.get ()))
return location;
/* Otherwise, the user _only_ specified optional flags like
"-qualified", otherwise string_to_explicit_location would
have thrown an error. Save the flags for "basic" linespec
parsing below and discard the explicit location. */
match_type = EL_EXPLICIT (location)->func_name_match_type;
}
return location;
/* Everything else is a "basic" linespec, address, or probe
location. */
return string_to_event_location_basic (stringp, language, match_type);
}
/* See description in location.h. */