Fix 'catch exception' with -flto

A user noticed that when an Ada program (including the runtime) is
compiled with -flto, then "catch exception" does not work -- even
though setting the equivalent breakpoint by hand does work.

Looking into this, it turns out that GCC puts the exception functions
from the Ada runtime into a CU that uses the C language, not Ada.
Then, when trying to look up the relevant symbol,
lookup_name_info::search_name_hash uses the "verbatim" form of the
symbol name (like "<__gnat_debug_raise_exception>") rather than the
"<>"-less form, causing the symbol not to be found.

This patch fixes the problem in two steps.

First, lookup_name_info::search_name_hash is changed to use the same
hack that language_defn::get_symbol_name_matcher uses.  That is, when
the current language is Ada, verbatim-mode lookups are special-cased.
(This is a bit unfortunate; perhaps a better long term approach would
be to promote verbatim mode to a fundamental mode of
lookup_name_info.)

Second, although the above fixes the problem in the Ada language mode,
the code still fails in other languages.  However, due to the way
these lookups are coded in ada-lang.c, I think it makes sense to
temporarily set the current language to Ada in
create_ada_exception_catchpoint.

Tested on x86-64 Fedora 38.

A new test case that mimics the -flto scenario is included.

Reviewed-By: Alexandra Petlanova Hajkova <ahajkova@redhat.com>
This commit is contained in:
Tom Tromey
2024-08-14 07:45:59 -06:00
parent 6a4eb277b7
commit d2f6771173
5 changed files with 102 additions and 11 deletions

View File

@@ -12717,6 +12717,10 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
int enabled, int enabled,
int from_tty) int from_tty)
{ {
/* This works around an obscure issue when an Ada program is
compiled with LTO. */
scoped_restore_current_language save_language (language_ada);
std::unique_ptr<ada_catchpoint> c std::unique_ptr<ada_catchpoint> c
(new ada_catchpoint (gdbarch, ex_kind, (new ada_catchpoint (gdbarch, ex_kind,
cond_string.empty () ? nullptr : cond_string.c_str (), cond_string.empty () ? nullptr : cond_string.c_str (),

View File

@@ -1929,6 +1929,28 @@ lookup_name_info::match_any ()
return lookup_name; return lookup_name;
} }
/* See symtab.h. */
unsigned int
lookup_name_info::search_name_hash (language lang) const
{
/* This works around an obscure problem. If currently in Ada mode,
and the name is wrapped in '<...>' (indicating verbatim mode),
force the use of the Ada language here so that the '<' and '>'
will be removed. */
if (current_language->la_language == language_ada && ada ().verbatim_p ())
lang = language_ada;
/* Only compute each language's hash once. */
if (!m_demangled_hashes_p[lang])
{
m_demangled_hashes[lang]
= ::search_name_hash (lang, language_lookup_name (lang));
m_demangled_hashes_p[lang] = true;
}
return m_demangled_hashes[lang];
}
/* Compute the demangled form of NAME as used by the various symbol /* Compute the demangled form of NAME as used by the various symbol
lookup functions. The result can either be the input NAME lookup functions. The result can either be the input NAME
directly, or a pointer to a buffer owned by the STORAGE object. directly, or a pointer to a buffer owned by the STORAGE object.

View File

@@ -266,17 +266,7 @@ class lookup_name_info final
} }
/* Get the search name hash for searches in language LANG. */ /* Get the search name hash for searches in language LANG. */
unsigned int search_name_hash (language lang) const unsigned int search_name_hash (language lang) const;
{
/* Only compute each language's hash once. */
if (!m_demangled_hashes_p[lang])
{
m_demangled_hashes[lang]
= ::search_name_hash (lang, language_lookup_name (lang));
m_demangled_hashes_p[lang] = true;
}
return m_demangled_hashes[lang];
}
/* Get the search name for searches in language LANG. */ /* Get the search name for searches in language LANG. */
const char *language_lookup_name (language lang) const const char *language_lookup_name (language lang) const

View File

@@ -0,0 +1,40 @@
/* This test program is part of GDB, the GNU debugger.
Copyright 2024 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/>. */
/* We need a few extra functions here to ensure that the dictionary
for the global block has more than one slot. */
void f1 () { }
void f2 () { }
void f3 () { }
void f4 () { }
void
__gnat_debug_raise_exception ()
{
}
void
__gnat_begin_handler_v1 ()
{
}
int
main ()
{
return 0;
}

View File

@@ -0,0 +1,35 @@
# Copyright 2024 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 test mimics the situation where an Ada program (including the
# runtime) is built with -flto. In this situation, gcc emits the
# exception handling functions in the DWARF -- but in a CU that is
# marked as coming from "C". This then triggered a bug causing the
# Ada catchpoint code not to find the underlying runtime functions.
require allow_ada_tests
standard_testfile .c
if {[build_executable "failed to prepare" $testfile $srcfile] == -1} {
return -1
}
# Try this test in both the C and Ada language modes.
foreach_with_prefix lang {c ada} {
clean_restart $testfile
gdb_test_no_output "set lang $lang"
gdb_test "catch exception" "Catchpoint 1: all Ada exceptions"
}