static struct die_info *dwarf2_extension (struct die_info *die,
struct dwarf2_cu **);
+static die_info *follow_die_offset (const section_and_offset &target,
+ dwarf2_cu **ref_cu);
+
static struct die_info *follow_die_ref_or_sig (struct die_info *,
const struct attribute *,
struct dwarf2_cu **);
return name;
}
+/* A convenience structure that holds a CU and a DIE. */
+
+struct cu_die_pair
+{
+ die_info *die;
+ dwarf2_cu *cu;
+
+ /* Return true if this object holds a valid DIE. */
+ bool valid () const
+ {
+ return die != nullptr;
+ }
+
+ /* Compare two cu_die_pair objects. */
+ bool operator!= (const cu_die_pair &other) const
+ {
+ return die != other.die || cu != other.cu;
+ }
+};
+
+/* Follow the DW_AT_type reference, if any, from ORIG. The return
+ value will be valid only when DW_AT_type exists. In other cases,
+ including when the incoming ORIG is not valid, an invalid
+ cu_die_pair is returned. */
+
+static cu_die_pair
+follow_type (cu_die_pair orig)
+{
+ /* This simplifies the caller a little. */
+ if (!orig.valid ())
+ return {};
+
+ attribute *type_attr = dwarf2_attr (orig.die, DW_AT_type, orig.cu);
+ if (type_attr == nullptr || !type_attr->form_is_ref ())
+ return {};
+
+ cu_die_pair result = orig;
+ sect_offset sect_off = type_attr->get_ref_die_offset ();
+ const dwarf2_section_info §ion = get_section_for_ref (*type_attr,
+ orig.cu);
+ result.die = follow_die_offset ({ §ion, sect_off }, &result.cu);
+
+ /* Note that we do not check for DW_TAG_pointer_type here. GNAT, at
+ least, will emit recursive pointers that "indirect" via typedefs,
+ so checkpoint purely for pointer types would not find these. */
+ return result;
+}
+
+/* Return true if DIE is a self-referential pointer type; false
+ otherwise. CU is the origin of DIE. */
+
+static bool
+is_recursive_pointer (die_info *die, dwarf2_cu *cu)
+{
+ cu_die_pair tortoise { die, cu };
+ gdb_assert (tortoise.valid ());
+ cu_die_pair hare = follow_type (tortoise);
+
+ while (tortoise != hare)
+ {
+ tortoise = follow_type (tortoise);
+ hare = follow_type (follow_type (hare));
+ if (!tortoise.valid () || !hare.valid ())
+ return false;
+ }
+
+ return true;
+}
+
/* Extract all information from a DW_TAG_pointer_type DIE and add to
the user defined type vector. */
int byte_size;
struct type *target_type;
- target_type = die_type (die, cu);
+ /* In Ada, it's possible to create a self-referential pointer type.
+ These aren't useful, but nevertheless we take care to avoid a gdb
+ crash in this situation. Instead just turn these into a
+ pointer-to-void. */
+ if (is_recursive_pointer (die, cu))
+ {
+ type_allocator alloc (cu->per_objfile->objfile, cu->lang ());
+ target_type = alloc.new_type (TYPE_CODE_VOID, 0, nullptr);
+ }
+ else
+ target_type = die_type (die, cu);
/* The die_type call above may have already set the type for this DIE. */
type = get_die_type (die, cu);
--- /dev/null
+# Copyright 2025 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/>.
+
+# Test that recursive access types do not cause a crash.
+
+load_lib "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile prog
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} {
+ return
+}
+
+clean_restart ${testfile}
+
+# The bug was that even reading these types caused a crash.
+gdb_test_no_output "maint expand-symtabs"
--- /dev/null
+-- Copyright 2025 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/>.
+
+package Pack is
+ -- With GCC, this makes a directly self-referential pointer type.
+ type Direct;
+ subtype Sub is Direct;
+ type Direct is access Sub;
+
+ -- With GCC, this makes two mutually recursive pointer types.
+ type Second;
+ type First is access Second;
+ type Second is access First;
+end Pack;
--- /dev/null
+-- Copyright 2025 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/>.
+
+with Pack; use Pack;
+
+procedure Prog is
+ X : Direct := null;
+ Y : Second := new First;
+begin
+ null;
+end Prog;