Breakpoints in symbols with ABI tags (PR c++/19436)

Trying to set a breakpoint in a function with an ABI tag does not work
currently.  E.g., debugging gdb itself, we see this with the
"string_printf" function:

 (top-gdb) b string_print                               [TAB]
 (top-gdb) b string_printf[abi:cxx11](char const*, ...) [RET]
 No source file named string_printf[abi.
 Make breakpoint pending on future shared library load? (y or [n])

Quoting doesn't help:
 (top-gdb) b 'string_printf[abi:cxx11]'(char const*, ...)
 malformed linespec error: unexpected string, "(char const*, ...)"
 (top-gdb) b 'string_printf[abi:cxx11](char const*, ...)'
 No source file named string_printf[abi.
 Make breakpoint pending on future shared library load? (y or [n]) n

This patch fixes this, and takes it a bit further.

The actual symbol name as demangled by libiberty's demangler is really

 string_printf[abi:cxx11](char const*, ...)

however, this patch makes it possible to set the breakpoint with

 string_printf(char const*, ...)

too.  I.e., ignoring the ABI tag.

And to match, it teaches the completer to complete the symbol name
without the ABI tag, i.e.,

  "string_pri<TAB>"  -> "string_printf(char const*, ...)"

If however, you really want to break on a symbol with the tag, then
you simply start writing the tag, and GDB will preserve it, like:

  "string_printf[a<TAB>"  -> "string_printf[abi:cxx11](char const*, ...)"

Grows the gdb.linespec/ tests like this:

  -# of expected passes           8977
  +# of expected passes           9176

gdb/ChangeLog:
2017-11-29  Pedro Alves  <palves@redhat.com>

	PR c++/19436
	* NEWS: Mention setting breakpoints on functions with C++ ABI
	tags.
	* completer.h (completion_match_for_lcd) <match,
	mark_ignored_range>: New methods.
	<finish>: Consider ignored ranges.
	<clear>: Clear ignored ranges.
	<m_ignored_ranges, m_finished_storage>: New fields.
	* cp-support.c (cp_search_name_hash): Ignore ABI tags.
	(cp_symbol_name_matches_1, cp_fq_symbol_name_matches): Pass the
	completion_match_for_lcd pointer to strncmp_iw_with_mode.
	(test_cp_symbol_name_cmp): Add [abi:...] tags unit tests.
	* language.c (default_symbol_name_matcher): Pass the
	completion_match_for_lcd pointer to strncmp_iw_with_mode.
	* linespec.c (linespec_lexer_lex_string): Don't tokenize ABI tags.
	* utils.c (skip_abi_tag): New function.
	(strncmp_iw_with_mode): Add completion_match_for_lcd parameter.
	Handle ABI tags.
	* utils.h (strncmp_iw_with_mode): Add completion_match_for_lcd
	parameter.

gdb/testsuite/ChangeLog:
2017-11-29  Pedro Alves  <palves@redhat.com>

	PR c++/19436
	* gdb.linespec/cpls-abi-tag.cc: New file.
	* gdb.linespec/cpls-abi-tag.exp: New file.

gdb/doc/ChangeLog:
2017-11-29  Pedro Alves  <palves@redhat.com>

	PR c++/19436
	* gdb.texinfo (Debugging C Plus Plus): Document setting
	breakpoints in functions with ABI tags.
This commit is contained in:
Pedro Alves 2017-11-29 19:33:24 +00:00
parent a20714ff39
commit bd69330db8
13 changed files with 721 additions and 18 deletions

View File

@ -1,3 +1,49 @@
2017-11-29 Pedro Alves <palves@redhat.com>
PR c++/19436
* NEWS: Mention setting breakpoints on functions with C++ ABI
tags.
* completer.h (completion_match_for_lcd) <match,
mark_ignored_range>: New methods.
<finish>: Consider ignored ranges.
<clear>: Clear ignored ranges.
<m_ignored_ranges, m_finished_storage>: New fields.
* cp-support.c (cp_search_name_hash): Ignore ABI tags.
(cp_symbol_name_matches_1, cp_fq_symbol_name_matches): Pass the
completion_match_for_lcd pointer to strncmp_iw_with_mode.
(test_cp_symbol_name_cmp): Add [abi:...] tags unit tests.
* language.c (default_symbol_name_matcher): Pass the
completion_match_for_lcd pointer to strncmp_iw_with_mode.
* linespec.c (linespec_lexer_lex_string): Don't tokenize ABI tags.
* utils.c (skip_abi_tag): New function.
(strncmp_iw_with_mode): Add completion_match_for_lcd parameter.
Handle ABI tags.
* utils.h (strncmp_iw_with_mode): Add completion_match_for_lcd
parameter.
2017-11-29 Pedro Alves <palves@redhat.com>
PR c++/19436
* NEWS: Mention setting breakpoints on functions with C++ ABI
tags.
* completer.h (completion_match_for_lcd) <match,
mark_ignored_range>: New methods.
<finish>: Consider ignored ranges.
<clear>: Clear ignored ranges.
<m_ignored_ranges, m_finished_storage>: New fields.
* cp-support.c (cp_search_name_hash): Ignore ABI tags.
(cp_symbol_name_matches_1, cp_fq_symbol_name_matches): Pass the
completion_match_for_lcd pointer to strncmp_iw_with_mode.
(test_cp_symbol_name_cmp): Add [abi:...] tags unit tests.
* language.c (default_symbol_name_matcher): Pass the
completion_match_for_lcd pointer to strncmp_iw_with_mode.
* linespec.c (linespec_lexer_lex_string): Don't tokenize ABI tags.
* utils.c (skip_abi_tag): New function.
(strncmp_iw_with_mode): Add completion_match_for_lcd parameter.
Handle ABI tags.
* utils.h (strncmp_iw_with_mode): Add completion_match_for_lcd
parameter.
2017-11-29 Pedro Alves <palves@redhat.com>
* NEWS: Mention that breakpoints on C++ functions are now set on

View File

@ -72,6 +72,28 @@
program, the "break -q B::func" command sets a breakpoint on
"B::func", only.
* Breakpoints on functions marked with C++ ABI tags
GDB can now set breakpoints on functions marked with C++ ABI tags
(e.g., [abi:cxx11]). See here for a description of ABI tags:
https://developers.redhat.com/blog/2015/02/05/gcc5-and-the-c11-abi/
Functions with a C++11 abi tag are demangled/displayed like this:
function[abi:cxx11](int)
^^^^^^^^^^^
You can now set a breakpoint on such functions simply as if they had
no tag, like:
(gdb) b function(int)
Or if you need to disambiguate between tags, like:
(gdb) b function[abi:other_tag](int)
Tab completion was adjusted accordingly as well.
* Python Scripting
** New events gdb.new_inferior, gdb.inferior_deleted, and

View File

@ -122,28 +122,82 @@ private:
"b push_ba" on a C++ program usually completes to
std::vector<...>::push_back, std::string::push_back etc. In such
case, the symbol comparison routine will set the LCD match to point
into the "push_back" substring within the symbol's name string. */
into the "push_back" substring within the symbol's name string.
Also, in some cases, the symbol comparison routine will want to
ignore parts of the symbol name for LCD purposes, such as for
example symbols with abi tags in C++. In such cases, the symbol
comparison routine will set MARK_IGNORED_RANGE to mark the ignored
substrings of the matched string. The resulting LCD string with
the ignored parts stripped out is computed at the end of a
completion match sequence iff we had a positive match. */
class completion_match_for_lcd
{
public:
/* Get the resulting LCD, after a successful match. */
const char *match ()
{ return m_match; }
/* Set the match for LCD. See m_match's description. */
void set_match (const char *match)
{ m_match = match; }
/* Get the resulting LCD, after a successful match. */
/* Mark the range between [BEGIN, END) as ignored. */
void mark_ignored_range (const char *begin, const char *end)
{ m_ignored_ranges.emplace_back (begin, end); }
/* Get the resulting LCD, after a successful match. If there are
ignored ranges, then this builds a new string with the ignored
parts removed (and stores it internally). As such, the result of
this call is only good for the current completion match
sequence. */
const char *finish ()
{ return m_match; }
{
if (m_ignored_ranges.empty ())
return m_match;
else
{
m_finished_storage.clear ();
const char *prev = m_match;
for (const auto &range : m_ignored_ranges)
{
m_finished_storage.append (prev, range.first);
prev = range.second;
}
m_finished_storage.append (prev);
return m_finished_storage.c_str ();
}
}
/* Prepare for another completion matching sequence. */
void clear ()
{ m_match = NULL; }
{
m_match = NULL;
m_ignored_ranges.clear ();
}
private:
/* The completion match result for LCD. This is usually either a
pointer into to a substring within a symbol's name, or to the
storage of the pairing completion_match object. */
const char *m_match;
/* The ignored substring ranges within M_MATCH. E.g., if we were
looking for completion matches for C++ functions starting with
"functio"
and successfully match:
"function[abi:cxx11](int)"
the ignored ranges vector will contain an entry that delimits the
"[abi:cxx11]" substring, such that calling finish() results in:
"function(int)"
*/
std::vector<std::pair<const char *, const char *>> m_ignored_ranges;
/* Storage used by the finish() method, if it has to compute a new
string. */
std::string m_finished_storage;
};
/* Convenience aggregate holding info returned by the symbol name

View File

@ -1629,7 +1629,23 @@ cp_search_name_hash (const char *search_name)
if (prefix_len != 0)
search_name += prefix_len + 2;
return default_search_name_hash (search_name);
unsigned int hash = 0;
for (const char *string = search_name; *string != '\0'; ++string)
{
string = skip_spaces (string);
if (*string == '(')
break;
/* Ignore ABI tags such as "[abi:cxx11]. */
if (*string == '['
&& startswith (string + 1, "abi:")
&& string[5] != ':')
break;
hash = SYMBOL_HASH_NEXT (hash, *string);
}
return hash;
}
/* Helper for cp_symbol_name_matches (i.e., symbol_name_matcher_ftype
@ -1674,11 +1690,13 @@ cp_symbol_name_matches_1 (const char *symbol_search_name,
completion_match_result *comp_match_res)
{
const char *sname = symbol_search_name;
completion_match_for_lcd *match_for_lcd
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
while (true)
{
if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
mode, language_cplus) == 0)
mode, language_cplus, match_for_lcd) == 0)
{
if (comp_match_res != NULL)
{
@ -1728,14 +1746,15 @@ cp_fq_symbol_name_matches (const char *symbol_search_name,
{
/* Get the demangled name. */
const std::string &name = lookup_name.cplus ().lookup_name ();
completion_match_for_lcd *match_for_lcd
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
strncmp_iw_mode mode = (lookup_name.completion_mode ()
? strncmp_iw_mode::NORMAL
: strncmp_iw_mode::MATCH_PARAMS);
if (strncmp_iw_with_mode (symbol_search_name,
name.c_str (), name.size (),
mode, language_cplus) == 0)
mode, language_cplus, match_for_lcd) == 0)
{
if (comp_match_res != NULL)
comp_match_res->set_match (symbol_search_name);
@ -1950,6 +1969,32 @@ test_cp_symbol_name_matches ()
CHECK_NOT_MATCH_C ("foo::function()", "::function()");
CHECK_NOT_MATCH_C ("foo::function(int)", "::function()");
CHECK_NOT_MATCH_C ("foo::function(int)", "::function(int)");
/* Test ABI tag matching/ignoring. */
/* If the symbol name has an ABI tag, but the lookup name doesn't,
then the ABI tag in the symbol name is ignored. */
CHECK_MATCH_C ("function[abi:foo]()", "function");
CHECK_MATCH_C ("function[abi:foo](int)", "function");
CHECK_MATCH_C ("function[abi:foo]()", "function ()");
CHECK_NOT_MATCH_C ("function[abi:foo]()", "function (int)");
CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo]");
CHECK_MATCH_C ("function[abi:foo](int)", "function[abi:foo]");
CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo] ()");
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function");
CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function");
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo]");
CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function[abi:foo]");
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] ()");
CHECK_NOT_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] (int)");
CHECK_MATCH_C ("function [abi:foo][abi:bar] ( )", "function [abi:foo]");
/* If the symbol name does not have an ABI tag, while the lookup
name has one, then there's no match. */
CHECK_NOT_MATCH_C ("function()", "function[abi:foo]()");
CHECK_NOT_MATCH_C ("function()", "function[abi:foo]");
}
/* If non-NULL, return STR wrapped in quotes. Otherwise, return a

View File

@ -1,3 +1,9 @@
2017-11-29 Pedro Alves <palves@redhat.com>
PR c++/19436
* gdb.texinfo (Debugging C Plus Plus): Document setting
breakpoints in functions with ABI tags.
2017-11-29 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Linespec Locations): Document how "function" is

View File

@ -15128,6 +15128,49 @@ the same notation that is used to declare such symbols in C@t{++}: type
also use the @value{GDBN} command-line word completion facilities to list the
available choices, or to finish the type list for you.
@xref{Completion,, Command Completion}, for details on how to do this.
@item @r{Breakpoints in functions with ABI tags}
The GNU C@t{++} compiler introduced the notion of ABI ``tags'', which
correspond to changes in the ABI of a type, function, or variable that
would not otherwise be reflected in a mangled name. See
@url{https://developers.redhat.com/blog/2015/02/05/gcc5-and-the-c11-abi/}
for more detail.
The ABI tags are visible in C@t{++} demangled names. For example, a
function that returns a std::string:
@smallexample
std::string function(int);
@end smallexample
@noindent
when compiled for the C++11 ABI is marked with the @code{cxx11} ABI
tag, and @value{GDBN} displays the symbol like this:
@smallexample
function[abi:cxx11](int)
@end smallexample
You can set a breakpoint on such functions simply as if they had no
tag. For example:
@smallexample
(gdb) b function(int)
Breakpoint 2 at 0x40060d: file main.cc, line 10.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x0040060d in function[abi:cxx11](int)
at main.cc:10
@end smallexample
On the rare occasion you need to disambiguate between different ABI
tags, you can do so by simply including the ABI tag in the function
name, like:
@smallexample
(@value{GDBP}) b ambiguous[abi:other_tag](int)
@end smallexample
@end table
@node Decimal Floating Point

View File

@ -707,13 +707,14 @@ default_symbol_name_matcher (const char *symbol_search_name,
completion_match_result *comp_match_res)
{
const std::string &name = lookup_name.name ();
completion_match_for_lcd *match_for_lcd
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
strncmp_iw_mode mode = (lookup_name.completion_mode ()
? strncmp_iw_mode::NORMAL
: strncmp_iw_mode::MATCH_PARAMS);
if (strncmp_iw_with_mode (symbol_search_name, name.c_str (), name.size (),
mode, language_minimal) == 0)
mode, language_minimal, match_for_lcd) == 0)
{
if (comp_match_res != NULL)
comp_match_res->set_match (symbol_search_name);

View File

@ -745,6 +745,11 @@ linespec_lexer_lex_string (linespec_parser *parser)
if (PARSER_STREAM (parser)[1] == ':')
++(PARSER_STREAM (parser));
/* Do not tokenize ABI tags such as "[abi:cxx11]". */
else if (PARSER_STREAM (parser) - start > 4
&& startswith (PARSER_STREAM (parser) - 4, "[abi"))
++(PARSER_STREAM (parser));
/* Do not tokenify if the input length so far is one
(i.e, a single-letter drive name) and the next character
is a directory separator. This allows Windows-style

View File

@ -1,3 +1,9 @@
2017-11-29 Pedro Alves <palves@redhat.com>
PR c++/19436
* gdb.linespec/cpls-abi-tag.cc: New file.
* gdb.linespec/cpls-abi-tag.exp: New file.
2017-11-29 Pedro Alves <palves@redhat.com>
* gdb.base/langs.exp: Use -qualified.

View File

@ -0,0 +1,93 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2017 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/>. */
#define ABI1 __attribute__ ((abi_tag ("tag1")))
#define ABI2 __attribute__ ((abi_tag ("tag2")))
#define ABI3 __attribute__ ((abi_tag ("tag3")))
void ABI1
test_abi_tag_function (int)
{
}
void ABI1
test_abi_tag_ovld_function ()
{
}
void ABI1
test_abi_tag_ovld_function (int)
{
}
/* Code for the overload functions, different ABI tag test. */
void
test_abi_tag_ovld2_function ()
{
}
void ABI1
test_abi_tag_ovld2_function (short)
{
}
void ABI2
test_abi_tag_ovld2_function (int)
{
}
void ABI2
test_abi_tag_ovld2_function (long)
{
}
struct ABI1 test_abi_tag_struct
{
ABI2 test_abi_tag_struct ();
ABI2 ~test_abi_tag_struct ();
};
test_abi_tag_struct::test_abi_tag_struct ()
{}
test_abi_tag_struct::~test_abi_tag_struct ()
{}
ABI3 test_abi_tag_struct s;
/* Code for the abi-tag in parameters test. */
struct ABI2 abi_tag_param_struct1
{};
struct ABI2 abi_tag_param_struct2
{};
void
test_abi_tag_in_params (abi_tag_param_struct1)
{}
void
test_abi_tag_in_params (abi_tag_param_struct1, abi_tag_param_struct2)
{}
int
main ()
{
return 0;
}

View File

@ -0,0 +1,286 @@
# Copyright 2017 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/>.
# This file is part of the gdb testsuite.
# Test ABI tag support in linespecs.
load_lib completion-support.exp
standard_testfile cpls-abi-tag.cc
if {[prepare_for_testing "failed to prepare" $testfile \
[list $srcfile] {c++ debug}]} {
return -1
}
gdb_test_no_output "set max-completions unlimited"
# Check that the explicit location completer manages to find the next
# option name after a -function option, when the -function's argument
# is a function with an ABI tag.
proc check_explicit_skips_function_argument {function} {
test_gdb_complete_unique \
"b -function $function -sour" \
"b -function $function -source"
}
# The ABI tag tests.
proc_with_prefix test_abi_tag {} {
with_test_prefix "completion" {
foreach cmd_prefix {"b" "b -function"} {
# Complete all prefixes between "_funcio" and the full
# prototype. The ABI tag is not considered for actual
# completion.
with_test_prefix "skip tag" {
# set location "test_abi_tag_function\[abi:tag1\](int)"
set location "test_abi_tag_function(int)"
set line "$cmd_prefix $location"
set start [index_after "_functio" $line]
test_complete_prefix_range $line $start
}
# Now the same, but start completing at the [. In that case,
# GDB considers the ABI tag as part of actual completion.
with_test_prefix "at tag" {
set location "test_abi_tag_function\[abi:tag1\](int)"
set line "$cmd_prefix $location"
set start [index_after "_function" $line]
test_complete_prefix_range $line $start
}
# Same, but with extra spaces. Note that the original spaces in
# the input line are preserved after completion.
with_test_prefix "spaces" {
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_function \[abi:tag1\] (" \
"$cmd_prefix test_abi_tag_function \[abi:tag1\] (int)"
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_function \[abi:tag1\] ( int " \
"$cmd_prefix test_abi_tag_function \[abi:tag1\] ( int )"
}
}
}
with_test_prefix "set breakpoints" {
foreach cmd_prefix {"b" "b -function"} {
# Test setting breakpoints. If the symbol name has an ABI
# tag, but the input linespec doesn't, then the ABI tag in the
# symbol name is ignored.
set linespec_list {
"test_abi_tag_function"
"test_abi_tag_function[abi:tag1]"
"test_abi_tag_function[abi:tag1](int)"
"test_abi_tag_function [abi:tag1]"
"test_abi_tag_function [abi:tag1] ( int )"
"test_abi_tag_function(int)"
"test_abi_tag_function (int)"
"test_abi_tag_function ( int )"
}
foreach linespec $linespec_list {
check_bp_locations_match_list \
"$cmd_prefix $linespec" [list $location]
}
}
}
with_test_prefix "set breakpoints wrong ABI tag" {
foreach cmd_prefix {"b" "b -function"} {
# Test setting breakpoints with the wrong ABI tag. Should
# fail to create the breakpoints. Completion should not find
# any match either.
set linespec_list {
"test_abi_tag_function[abi:tag2]"
"test_abi_tag_function[abi:tag2](int)"
"test_abi_tag_function [abi:tag2]"
"test_abi_tag_function [abi:tag2] ( int )"
}
foreach linespec $linespec_list {
check_setting_bp_fails "$cmd_prefix $linespec"
test_gdb_complete_none "$cmd_prefix $linespec"
}
}
}
# Test completion of overloaded functions with ABI tags.
with_test_prefix "completion of overloaded functions" {
foreach cmd_prefix {"b" "b -function"} {
set completion_list {
"test_abi_tag_ovld_function[abi:tag1]()"
"test_abi_tag_ovld_function[abi:tag1](int)"
}
# If the input string does not include the ABI tag, then
# actual completion ignores it.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_ovld_f" "unction(" \
$completion_list
# Otherwise, it's considered.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_ovld_function\[" "abi:tag1\](" \
$completion_list
}
}
# Test setting breakpoints on overloaded functions with ABI tags.
with_test_prefix "breakpoints on overloaded functions" {
foreach cmd_prefix {"b" "b -function"} {
set completion_list {
"test_abi_tag_ovld_function[abi:tag1]()"
"test_abi_tag_ovld_function[abi:tag1](int)"
}
set location_list {
"test_abi_tag_ovld_function"
"test_abi_tag_ovld_function[abi:tag1]"
}
foreach linespec $location_list {
check_bp_locations_match_list \
"$cmd_prefix $linespec" $completion_list
}
}
}
with_test_prefix "completion of overloaded functions different abi" {
foreach cmd_prefix {"b" "b -function"} {
# Test completion of overloaded functions with ABI tags.
set completion_list {
"test_abi_tag_ovld2_function()"
"test_abi_tag_ovld2_function[abi:tag1](short)"
"test_abi_tag_ovld2_function[abi:tag2](int)"
"test_abi_tag_ovld2_function[abi:tag2](long)"
}
# If the input string does not include the ABI tag, then
# actual completion ignores it.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_ovld2_f" "unction(" \
$completion_list
# Otherwise, it's considered. Match stops at the part of
# the tag that diverges, and the completion list only
# shows matches with ABI tags.
set completion_list {
"test_abi_tag_ovld2_function[abi:tag1](short)"
"test_abi_tag_ovld2_function[abi:tag2](int)"
"test_abi_tag_ovld2_function[abi:tag2](long)"
}
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_ovld2_function\[" "abi:tag" \
$completion_list
# If you disambiguate, matches include only locations for
# the specified tag.
set completion_list {
"test_abi_tag_ovld2_function[abi:tag2](int)"
"test_abi_tag_ovld2_function[abi:tag2](long)"
}
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_ovld2_function\[abi:tag2" "\](" \
$completion_list
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_ovld2_function\[abi:tag1" \
"$cmd_prefix test_abi_tag_ovld2_function\[abi:tag1\](short)"
}
}
with_test_prefix "completion of struct prefixes with tags" {
foreach cmd_prefix {"b" "b -function"} {
# Test completion of methods of structs with ABI tags.
set completion_list {
"test_abi_tag_struct[abi:tag1]::test_abi_tag_struct[abi:tag2]()"
"test_abi_tag_struct[abi:tag1]::~test_abi_tag_struct[abi:tag2]()"
}
# If the input string does not include the ABI tag, then
# actual completion ignores it.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_struc" "t::" \
$completion_list
# Otherwise, it's considered.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_struct\[" "abi:tag1\]::" \
$completion_list
# Mix and match different abi tag positions.
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_struct::t" \
"$cmd_prefix test_abi_tag_struct::test_abi_tag_struct()"
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_struct\[abi:tag1\]::t" \
"$cmd_prefix test_abi_tag_struct\[abi:tag1\]::test_abi_tag_struct()"
test_gdb_complete_unique \
"$cmd_prefix test_abi_tag_struct\[abi:tag1\]::test_abi_tag_struct\[" \
"$cmd_prefix test_abi_tag_struct\[abi:tag1\]::test_abi_tag_struct\[abi:tag2\]()"
}
}
with_test_prefix "abi tag in parameters" {
foreach cmd_prefix {"b" "b -function"} {
# Complete all prefixes between "_funcio" and the full
# prototype. The ABI tag is not considered for actual
# completion.
set completion_list {
"test_abi_tag_in_params(abi_tag_param_struct1[abi:tag2])"
"test_abi_tag_in_params(abi_tag_param_struct1[abi:tag2], abi_tag_param_struct2[abi:tag2])"
}
# If the input string does not include the ABI tag, then
# actual completion ignores it.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_in_para" "ms(abi_tag_param_struct1" \
$completion_list
# If OTOH the input string includes the ABI tag, then it
# is considered.
test_gdb_complete_multiple \
"$cmd_prefix " "test_abi_tag_in_params(abi_tag_param_struct1\[ab" "i:tag2\]"\
$completion_list
set location_list {
"test_abi_tag_in_params(abi_tag_param_struct1[abi:tag2], abi_tag_param_struct2[abi:tag2])"
}
set tags {"" "\[abi:tag2\]"}
foreach tag1 $tags {
foreach tag2 $tags {
set linespec "test_abi_tag_in_params(abi_tag_param_struct1${tag1}, abi_tag_param_struct2${tag2})"
check_bp_locations_match_list \
"$cmd_prefix $linespec" $location_list
}
}
}
}
# Check that the explicit location completer manages to find the
# option name after -function, when the -function's argument is a
# function with an ABI tag.
check_explicit_skips_function_argument \
"test_abi_tag_function\[abi:unknown\](int)"
}
test_abi_tag

View File

@ -2247,12 +2247,40 @@ cp_is_operator (const char *string, const char *start)
&& !valid_identifier_name_char (string[CP_OPERATOR_LEN]));
}
/* If *NAME points at an ABI tag, skip it and return true. Otherwise
leave *NAME unmodified and return false. (see GCC's abi_tag
attribute), such names are demangled as e.g.,
"function[abi:cxx11]()". */
static bool
skip_abi_tag (const char **name)
{
const char *p = *name;
if (startswith (p, "[abi:"))
{
p += 5;
while (valid_identifier_name_char (*p))
p++;
if (*p == ']')
{
p++;
*name = p;
return true;
}
}
return false;
}
/* See utils.h. */
int
strncmp_iw_with_mode (const char *string1, const char *string2,
size_t string2_len, strncmp_iw_mode mode,
enum language language)
enum language language,
completion_match_for_lcd *match_for_lcd)
{
const char *string1_start = string1;
const char *end_str2 = string2 + string2_len;
@ -2271,6 +2299,37 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
skip_spaces = false;
}
/* Skip [abi:cxx11] tags in the symbol name if the lookup name
doesn't include them. E.g.:
string1: function[abi:cxx1](int)
string2: function
string1: function[abi:cxx1](int)
string2: function(int)
string1: Struct[abi:cxx1]::function()
string2: Struct::function()
string1: function(Struct[abi:cxx1], int)
string2: function(Struct, int)
*/
if (string2 == end_str2
|| (*string2 != '[' && !valid_identifier_name_char (*string2)))
{
const char *abi_start = string1;
/* There can be more than one tag. */
while (*string1 == '[' && skip_abi_tag (&string1))
;
if (match_for_lcd != NULL && abi_start != string1)
match_for_lcd->mark_ignored_range (abi_start, string1);
while (isspace (*string1))
string1++;
}
if (*string1 == '\0' || string2 == end_str2)
break;
@ -2405,7 +2464,40 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
if (string2 == end_str2)
{
if (mode == strncmp_iw_mode::NORMAL)
return 0;
{
/* Strip abi tag markers from the matched symbol name.
Usually the ABI marker will be found on function name
(automatically added because the function returns an
object marked with an ABI tag). However, it's also
possible to see a marker in one of the function
parameters, for example.
string2 (lookup name):
func
symbol name:
function(some_struct[abi:cxx11], int)
and for completion LCD computation we want to say that
the match was for:
function(some_struct, int)
*/
if (match_for_lcd != NULL)
{
while ((string1 = strstr (string1, "[abi:")) != NULL)
{
const char *abi_start = string1;
/* There can be more than one tag. */
while (skip_abi_tag (&string1) && *string1 == '[')
;
if (abi_start != string1)
match_for_lcd->mark_ignored_range (abi_start, string1);
}
}
return 0;
}
else
return (*string1 != '\0' && *string1 != '(');
}

View File

@ -49,15 +49,19 @@ enum class strncmp_iw_mode
/* Helper for strcmp_iw and strncmp_iw. Exported so that languages
can implement both NORMAL and MATCH_PARAMS variants in a single
function and defer part of the work to strncmp_iw_with_mode.
LANGUAGE is used to implement some context-sensitive
language-specific comparisons. For example, for C++,
"string1=operator()" should not match "string2=operator" even in
MATCH_PARAMS mode. */
extern int strncmp_iw_with_mode (const char *string1,
const char *string2,
size_t string2_len,
strncmp_iw_mode mode,
enum language language);
MATCH_PARAMS mode.
MATCH_FOR_LCD is passed down so that the function can mark parts of
the symbol name as ignored for completion matching purposes (e.g.,
to handle abi tags). */
extern int strncmp_iw_with_mode
(const char *string1, const char *string2, size_t string2_len,
strncmp_iw_mode mode, enum language language,
completion_match_for_lcd *match_for_lcd = NULL);
/* Do a strncmp() type operation on STRING1 and STRING2, ignoring any
differences in whitespace. STRING2_LEN is STRING2's length.