aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/Makefile.in11
-rw-r--r--gdb/NEWS8
-rw-r--r--gdb/README3
-rw-r--r--gdb/aarch64-linux-tdep.c2
-rw-r--r--gdb/aarch64-tdep.c4
-rw-r--r--gdb/ada-lang.c12
-rw-r--r--gdb/ada-varobj.c8
-rw-r--r--gdb/addrmap.c81
-rw-r--r--gdb/addrmap.h29
-rw-r--r--gdb/alpha-tdep.c2
-rw-r--r--gdb/amd64-fbsd-nat.c4
-rw-r--r--gdb/amd64-linux-tdep.c2
-rw-r--r--gdb/amd64-tdep.c2
-rw-r--r--gdb/arm-linux-nat.c2
-rw-r--r--gdb/arm-linux-tdep.c4
-rw-r--r--gdb/arm-pikeos-tdep.c17
-rw-r--r--gdb/arm-tdep.c4
-rw-r--r--gdb/bcache.c2
-rw-r--r--gdb/bcache.h2
-rw-r--r--gdb/bfin-tdep.c2
-rw-r--r--gdb/bpf-tdep.c2
-rw-r--r--gdb/breakpoint.c43
-rw-r--r--gdb/breakpoint.h2
-rw-r--r--gdb/bsd-uthread.c2
-rw-r--r--gdb/btrace.c14
-rw-r--r--gdb/buildsym.h2
-rw-r--r--gdb/c-lang.c32
-rw-r--r--gdb/c-lang.h38
-rw-r--r--gdb/cli/cli-script.c63
-rw-r--r--gdb/cli/cli-script.h10
-rw-r--r--gdb/coffread.c2
-rw-r--r--gdb/command.h2
-rw-r--r--gdb/compile/compile-internal.h39
-rw-r--r--gdb/compile/compile-object-load.c26
-rw-r--r--gdb/compile/compile.c81
-rw-r--r--gdb/completer.c2
-rw-r--r--gdb/completer.h2
-rw-r--r--gdb/config.in3
-rwxr-xr-xgdb/configure39
-rw-r--r--gdb/configure.ac20
-rw-r--r--gdb/contrib/codespell-ignore-words.txt3
-rw-r--r--gdb/contrib/common-misspellings.txt30
-rw-r--r--gdb/contrib/setup.cfg6
-rwxr-xr-xgdb/contrib/spellcheck.sh536
-rwxr-xr-xgdb/copyright.py210
-rw-r--r--gdb/cp-namespace.c2
-rw-r--r--gdb/cp-valprint.c2
-rw-r--r--gdb/cris-tdep.c4
-rw-r--r--gdb/csky-tdep.c4
-rw-r--r--gdb/data-directory/Makefile.in1
-rw-r--r--gdb/dbxread.c20
-rw-r--r--gdb/dicos-tdep.c41
-rw-r--r--gdb/displaced-stepping.h2
-rw-r--r--gdb/dtrace-probe.c2
-rw-r--r--gdb/dwarf2/abbrev-table-cache.h3
-rw-r--r--gdb/dwarf2/aranges.c10
-rw-r--r--gdb/dwarf2/cooked-index-entry.c242
-rw-r--r--gdb/dwarf2/cooked-index-entry.h258
-rw-r--r--gdb/dwarf2/cooked-index-shard.c331
-rw-r--r--gdb/dwarf2/cooked-index-shard.h134
-rw-r--r--gdb/dwarf2/cooked-index-storage.c84
-rw-r--r--gdb/dwarf2/cooked-index-storage.h131
-rw-r--r--gdb/dwarf2/cooked-index-worker.c255
-rw-r--r--gdb/dwarf2/cooked-index-worker.h305
-rw-r--r--gdb/dwarf2/cooked-index.c693
-rw-r--r--gdb/dwarf2/cooked-index.h499
-rw-r--r--gdb/dwarf2/cooked-indexer.c6
-rw-r--r--gdb/dwarf2/cooked-indexer.h8
-rw-r--r--gdb/dwarf2/loc.c12
-rw-r--r--gdb/dwarf2/parent-map.c2
-rw-r--r--gdb/dwarf2/read-debug-names.c69
-rw-r--r--gdb/dwarf2/read.c234
-rw-r--r--gdb/dwarf2/read.h17
-rw-r--r--gdb/elfread.c37
-rw-r--r--gdb/frame-base.h2
-rw-r--r--gdb/frame.c17
-rw-r--r--gdb/frame.h2
-rw-r--r--gdb/ft32-tdep.c2
-rw-r--r--gdb/gdb_bfd.c55
-rw-r--r--gdb/gdb_bfd.h12
-rw-r--r--gdb/gdbarch-selftests.c3
-rw-r--r--gdb/gdbarch.h2
-rw-r--r--gdb/gdbthread.h4
-rw-r--r--gdb/gnu-v3-abi.c2
-rw-r--r--gdb/go32-nat.c2
-rwxr-xr-xgdb/gstack-1.in8
-rw-r--r--gdb/h8300-tdep.c2
-rw-r--r--gdb/hppa-linux-tdep.c2
-rw-r--r--gdb/i386-fbsd-nat.c4
-rw-r--r--gdb/i386-linux-tdep.c6
-rw-r--r--gdb/i386-sol2-nat.c2
-rw-r--r--gdb/i386-tdep.c4
-rw-r--r--gdb/ia64-tdep.c8
-rw-r--r--gdb/ia64-vms-tdep.c2
-rw-r--r--gdb/inf-loop.c2
-rw-r--r--gdb/infcall.c2
-rw-r--r--gdb/infrun.c2
-rw-r--r--gdb/iq2000-tdep.c2
-rw-r--r--gdb/language.c8
-rw-r--r--gdb/language.h32
-rw-r--r--gdb/linux-nat.c4
-rw-r--r--gdb/linux-record.c6
-rw-r--r--gdb/linux-record.h6
-rw-r--r--gdb/linux-tdep.c4
-rw-r--r--gdb/loongarch-linux-tdep.c4
-rw-r--r--gdb/machoread.c2
-rw-r--r--gdb/main.c2
-rw-r--r--gdb/maint-test-options.c12
-rw-r--r--gdb/mdebugread.c8
-rw-r--r--gdb/mips-tdep.c2
-rw-r--r--gdb/moxie-tdep.c2
-rw-r--r--gdb/nds32-tdep.c2
-rw-r--r--gdb/observable.h6
-rw-r--r--gdb/p-exp.y2
-rw-r--r--gdb/python/lib/gdb/dap/__init__.py1
-rw-r--r--gdb/python/lib/gdb/dap/completions.py60
-rw-r--r--gdb/python/lib/gdb/dap/server.py21
-rw-r--r--gdb/record-full.c4
-rw-r--r--gdb/regcache.c23
-rw-r--r--gdb/remote.c2
-rw-r--r--gdb/riscv-tdep.c2
-rw-r--r--gdb/rs6000-tdep.c4
-rw-r--r--gdb/run-on-main-thread.c2
-rw-r--r--gdb/rust-lang.c13
-rw-r--r--gdb/s390-tdep.c4
-rw-r--r--gdb/selftest-arch.c19
-rw-r--r--gdb/selftest-arch.h5
-rw-r--r--gdb/ser-mingw.c4
-rw-r--r--gdb/ser-unix.c2
-rw-r--r--gdb/solib-darwin.c18
-rw-r--r--gdb/solib-rocm.c2
-rw-r--r--gdb/solib.c76
-rw-r--r--gdb/sparc-obsd-tdep.c2
-rw-r--r--gdb/sparc-sol2-nat.c2
-rw-r--r--gdb/sparc64-obsd-tdep.c2
-rw-r--r--gdb/stabsread.c10
-rw-r--r--gdb/stabsread.h2
-rw-r--r--gdb/stack.c2
-rw-r--r--gdb/stap-probe.c2
-rw-r--r--gdb/symfile.c2
-rw-r--r--gdb/symtab.c2
-rw-r--r--gdb/testsuite/gdb.ada/array_of_variant.exp2
-rw-r--r--gdb/testsuite/gdb.base/filename-completion.exp14
-rw-r--r--gdb/testsuite/gdb.base/gstack.exp6
-rw-r--r--gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp148
-rw-r--r--gdb/testsuite/gdb.base/options.exp17
-rw-r--r--gdb/testsuite/gdb.base/set-solib-absolute-prefix.c32
-rw-r--r--gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp51
-rw-r--r--gdb/testsuite/gdb.base/shlib-unload.exp69
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-inherit.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-member.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-method.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-namespace.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-nested.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-print.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus-virtual.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-cplus.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-ifunc.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-ops.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-print.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-setjmp.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile-tls.exp2
-rw-r--r--gdb/testsuite/gdb.compile/compile.exp2
-rw-r--r--gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c22
-rw-r--r--gdb/testsuite/gdb.mi/mi-dprintf-modified.c55
-rw-r--r--gdb/testsuite/gdb.mi/mi-dprintf-modified.exp119
-rw-r--r--gdb/testsuite/gdb.testsuite/version-compare.exp74
-rw-r--r--gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c7
-rw-r--r--gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp10
-rw-r--r--gdb/testsuite/lib/ada.exp10
-rw-r--r--gdb/testsuite/lib/compile-support.exp3
-rw-r--r--gdb/testsuite/lib/gdb-utils.exp5
-rw-r--r--gdb/testsuite/lib/gdb.exp38
-rw-r--r--gdb/top.c2
-rw-r--r--gdb/utils.c2
-rw-r--r--gdb/value.c8
-rw-r--r--gdb/value.h2
-rw-r--r--gdb/varobj.c2
-rw-r--r--gdb/vax-tdep.c2
-rw-r--r--gdb/windows-nat.h4
-rw-r--r--gdb/xcoffread.c4
-rw-r--r--gdb/xstormy16-tdep.c2
-rw-r--r--gdb/xtensa-tdep.c2
185 files changed, 3151 insertions, 2950 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8f6df5b..0c4102d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1097,7 +1097,9 @@ COMMON_SFILES = \
dwarf2/attribute.c \
dwarf2/comp-unit-head.c \
dwarf2/cooked-index.c \
- dwarf2/cooked-index-storage.c \
+ dwarf2/cooked-index-entry.c \
+ dwarf2/cooked-index-shard.c \
+ dwarf2/cooked-index-worker.c \
dwarf2/cooked-indexer.c \
dwarf2/cu.c \
dwarf2/die.c \
@@ -1356,7 +1358,9 @@ HFILES_NO_SRCDIR = \
dummy-frame.h \
dwarf2/aranges.h \
dwarf2/cooked-index.h \
- dwarf2/cooked-index-storage.h \
+ dwarf2/cooked-index-entry.h \
+ dwarf2/cooked-index-shard.h \
+ dwarf2/cooked-index-worker.h \
dwarf2/cooked-indexer.h \
dwarf2/cu.h \
dwarf2/frame-tailcall.h \
@@ -1912,8 +1916,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
$(patsubst %.c,%.o,$(COMMON_SFILES)) \
$(SUBDIR_CLI_OBS) \
$(SUBDIR_MI_OBS) \
- $(SUBDIR_TARGET_OBS) \
- $(SUBDIR_GCC_COMPILE_OBS)
+ $(SUBDIR_TARGET_OBS)
SUBDIRS = doc @subdirs@ data-directory
CLEANDIRS = $(SUBDIRS)
diff --git a/gdb/NEWS b/gdb/NEWS
index 2fdb849..6a557bb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
*** Changes since GDB 16
+* Debugger Adapter Protocol changes
+
+ ** GDB now supports the "completions" request.
+
* "set style" commands now supports numeric format for basic colors
from 0 to 255 and #RRGGBB format for TrueColor.
@@ -108,6 +112,10 @@ qXfer:threads:read
* Support for stabs debugging format and the a.out/dbx object format is
deprecated, and will be removed in GDB 18.
+* A new configure option was added, allowing support for the compile
+ subsystem to be disabled at configure time, in the form of
+ --disable-gdb-compile.
+
*** Changes in GDB 16
* Support for Nios II targets has been removed as this architecture
diff --git a/gdb/README b/gdb/README
index b6eb3f1..8836120 100644
--- a/gdb/README
+++ b/gdb/README
@@ -442,6 +442,9 @@ more obscure GDB `configure' options are not listed here.
Requires a curses library (ncurses and cursesX are also
supported).
+`--disable-gdb-compile'
+ Build GDB without support for the 'compile' command.
+
`--with-curses'
Use the curses library instead of the termcap library, for
text-mode terminal operations.
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 0b4ae7f..c825699 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -2275,7 +2275,7 @@ aarch64_canonicalize_syscall (enum aarch64_syscall syscall_number)
SYSCALL_MAP (clone);
SYSCALL_MAP (execve);
- SYSCALL_MAP_RENAME (mmap, gdb_sys_mmap2);
+ SYSCALL_MAP_RENAME (mmap, gdb_sys_old_mmap);
SYSCALL_MAP (fadvise64);
SYSCALL_MAP (swapon);
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index bd107b8..0561c93 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -2696,7 +2696,7 @@ aarch64_store_return_value (struct type *type, struct regcache *regs,
{
/* Integral values greater than one word are stored in
consecutive registers starting with r0. This will always
- be a multiple of the regiser size. */
+ be a multiple of the register size. */
int len = type->length ();
int regno = AARCH64_X0_REGNUM;
@@ -4344,7 +4344,7 @@ aarch64_initialize_sme_pseudo_names (struct gdbarch *gdbarch,
}
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called e.g. at program startup, when reading a core file, and when
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index a55ee12..041024a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1532,7 +1532,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
{
/* This is a X[bn]* sequence not separated from the previous
part of the name with a non-alpha-numeric character (in other
- words, immediately following an alpha-numeric character), then
+ words, immediately following an alphanumeric character), then
verify that it is placed at the end of the encoded name. If
not, then the encoding is not valid and we should abort the
decoding. Otherwise, just skip it, it is used in body-nested
@@ -3047,7 +3047,7 @@ ada_value_subscript (struct value *arr, int arity, struct value **ind)
Note: Unlike what one would expect, this function is used instead of
ada_value_subscript for basically all non-packed array types. The reason
- for this is that a side effect of doing our own pointer arithmetics instead
+ for this is that a side effect of doing our own pointer arithmetic instead
of relying on value_subscript is that there is no implicit typedef peeling.
This is important for arrays of array accesses, where it allows us to
preserve the fact that the array's element is an array access, where the
@@ -5435,7 +5435,7 @@ ada_add_block_renamings (std::vector<struct block_symbol> &result,
better in this case since, in DWARF, DW_AT_import is a DIE reference,
not a simple name. But in order to do this, we would need to enhance
the DWARF reader to associate a symbol to this renaming, instead of a
- name. So, for now, we do something simpler: re-use the C++/Fortran
+ name. So, for now, we do something simpler: reuse the C++/Fortran
namespace machinery. */
r_name = (renaming->alias != NULL
? renaming->alias
@@ -9802,7 +9802,7 @@ ada_value_cast (struct type *type, struct value *arg2)
The following description is a general guide as to what should be
done (and what should NOT be done) in order to evaluate an expression
involving such types, and when. This does not cover how the semantic
- information is encoded by GNAT as this is covered separatly. For the
+ information is encoded by GNAT as this is covered separately. For the
document used as the reference for the GNAT encoding, see exp_dbug.ads
in the GNAT sources.
@@ -11780,14 +11780,14 @@ ada_exception_support_info_sniffer (void)
return;
}
- /* Try the v0 exception suport info. */
+ /* Try the v0 exception support info. */
if (ada_has_this_exception_support (&exception_support_info_v0))
{
data->exception_info = &exception_support_info_v0;
return;
}
- /* Try our fallback exception suport info. */
+ /* Try our fallback exception support info. */
if (ada_has_this_exception_support (&exception_support_info_fallback))
{
data->exception_info = &exception_support_info_fallback;
diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
index 21412db..b188ea6 100644
--- a/gdb/ada-varobj.c
+++ b/gdb/ada-varobj.c
@@ -612,7 +612,7 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
{
std::string index_img = ada_varobj_scalar_image (index_type, real_index);
- /* Enumeration litterals by themselves are potentially ambiguous.
+ /* Enumeration literals by themselves are potentially ambiguous.
For instance, consider the following package spec:
package Pck is
@@ -620,10 +620,10 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
type Blood_Cells is (White, Red);
end Pck;
- In this case, the litteral "red" for instance, or even
- the fully-qualified litteral "pck.red" cannot be resolved
+ In this case, the literal "red" for instance, or even
+ the fully-qualified literal "pck.red" cannot be resolved
by itself. Type qualification is needed to determine which
- enumeration litterals should be used.
+ enumeration literals should be used.
The following variable will be used to contain the name
of the array index type when such type qualification is
diff --git a/gdb/addrmap.c b/gdb/addrmap.c
index 9eb330b..1fc95f3 100644
--- a/gdb/addrmap.c
+++ b/gdb/addrmap.c
@@ -178,6 +178,29 @@ addrmap_mutable::force_transition (CORE_ADDR addr)
}
+/* Compare keys as CORE_ADDR * values. */
+static int
+splay_compare_CORE_ADDR_ptr (splay_tree_key ak, splay_tree_key bk)
+{
+ CORE_ADDR a = * (CORE_ADDR *) ak;
+ CORE_ADDR b = * (CORE_ADDR *) bk;
+
+ /* We can't just return a-b here, because of over/underflow. */
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+
+
+static void
+xfree_wrapper (splay_tree_key key)
+{
+ xfree ((void *) key);
+}
+
void
addrmap_mutable::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
void *obj)
@@ -185,6 +208,10 @@ addrmap_mutable::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
splay_tree_node n, next;
void *prior_value;
+ if (tree == nullptr)
+ tree = splay_tree_new (splay_compare_CORE_ADDR_ptr, xfree_wrapper,
+ nullptr /* no delete value */);
+
/* If we're being asked to set all empty portions of the given
address range to empty, then probably the caller is confused.
(If that turns out to be useful in some cases, then we can change
@@ -233,6 +260,9 @@ addrmap_mutable::set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
void *
addrmap_mutable::do_find (CORE_ADDR addr) const
{
+ if (tree == nullptr)
+ return nullptr;
+
splay_tree_node n = splay_tree_lookup (addr);
if (n != nullptr)
{
@@ -287,16 +317,6 @@ addrmap_fixed::addrmap_fixed (struct obstack *obstack,
gdb_assert (num_transitions == transition_count);
}
-
-void
-addrmap_mutable::relocate (CORE_ADDR offset)
-{
- /* Not needed yet. */
- internal_error (_("addrmap_relocate is not implemented yet "
- "for mutable addrmaps"));
-}
-
-
/* This is a splay_tree_foreach_fn. */
static int
@@ -311,43 +331,20 @@ addrmap_mutable_foreach_worker (splay_tree_node node, void *data)
int
addrmap_mutable::do_foreach (addrmap_foreach_fn fn) const
{
- return splay_tree_foreach (tree, addrmap_mutable_foreach_worker, &fn);
-}
-
-
-/* Compare keys as CORE_ADDR * values. */
-static int
-splay_compare_CORE_ADDR_ptr (splay_tree_key ak, splay_tree_key bk)
-{
- CORE_ADDR a = * (CORE_ADDR *) ak;
- CORE_ADDR b = * (CORE_ADDR *) bk;
-
- /* We can't just return a-b here, because of over/underflow. */
- if (a < b)
- return -1;
- else if (a == b)
+ if (tree == nullptr)
return 0;
- else
- return 1;
-}
-
-
-static void
-xfree_wrapper (splay_tree_key key)
-{
- xfree ((void *) key);
+ return splay_tree_foreach (tree, addrmap_mutable_foreach_worker, &fn);
}
-addrmap_mutable::addrmap_mutable ()
- : tree (splay_tree_new (splay_compare_CORE_ADDR_ptr, xfree_wrapper,
- nullptr /* no delete value */))
-{
-}
-addrmap_mutable::~addrmap_mutable ()
+void
+addrmap_mutable::clear ()
{
if (tree != nullptr)
- splay_tree_delete (tree);
+ {
+ splay_tree_delete (tree);
+ tree = nullptr;
+ }
}
@@ -443,7 +440,7 @@ test_addrmap ()
CHECK_ADDRMAP_FIND (map, array, 13, 19, nullptr);
/* Create corresponding fixed addrmap. */
- struct addrmap *map2
+ addrmap_fixed *map2
= new (&temp_obstack) addrmap_fixed (&temp_obstack, map.get ());
SELF_CHECK (map2 != nullptr);
CHECK_ADDRMAP_FIND (map2, array, 0, 9, nullptr);
diff --git a/gdb/addrmap.h b/gdb/addrmap.h
index 95f6ec8..a2feb68 100644
--- a/gdb/addrmap.h
+++ b/gdb/addrmap.h
@@ -52,10 +52,6 @@ struct addrmap
void *find (CORE_ADDR addr)
{ return this->do_find (addr); }
- /* Relocate all the addresses in MAP by OFFSET. (This can be applied
- to either mutable or immutable maps.) */
- virtual void relocate (CORE_ADDR offset) = 0;
-
/* Call FN for every address in MAP, following an in-order traversal.
If FN ever returns a non-zero value, the iteration ceases
immediately, and the value is returned. Otherwise, this function
@@ -94,7 +90,8 @@ public:
addrmap_fixed (addrmap_fixed &&other) = default;
addrmap_fixed &operator= (addrmap_fixed &&) = default;
- void relocate (CORE_ADDR offset) override;
+ /* Relocate all the addresses in this map by OFFSET. */
+ void relocate (CORE_ADDR offset);
private:
void *do_find (CORE_ADDR addr) const override;
@@ -126,8 +123,12 @@ struct addrmap_mutable final : public addrmap
{
public:
- addrmap_mutable ();
- ~addrmap_mutable ();
+ addrmap_mutable () = default;
+ ~addrmap_mutable ()
+ {
+ clear ();
+ }
+
DISABLE_COPY_AND_ASSIGN (addrmap_mutable);
addrmap_mutable (addrmap_mutable &&other)
@@ -138,7 +139,13 @@ public:
addrmap_mutable &operator= (addrmap_mutable &&other)
{
- std::swap (tree, other.tree);
+ /* Handle self-move. */
+ if (this != &other)
+ {
+ clear ();
+ tree = other.tree;
+ other.tree = nullptr;
+ }
return *this;
}
@@ -181,7 +188,9 @@ public:
representation. */
void set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
void *obj);
- void relocate (CORE_ADDR offset) override;
+
+ /* Clear this addrmap. */
+ void clear ();
private:
void *do_find (CORE_ADDR addr) const override;
@@ -204,7 +213,7 @@ private:
function, we can't keep a freelist for keys. Since mutable
addrmaps are only used temporarily right now, we just leak keys
from deleted nodes; they'll be freed when the obstack is freed. */
- splay_tree tree;
+ splay_tree tree = nullptr;
/* Various helper methods. */
splay_tree_key allocate_key (CORE_ADDR addr);
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c
index 7201b72..bf3e8fc3 100644
--- a/gdb/alpha-tdep.c
+++ b/gdb/alpha-tdep.c
@@ -1705,7 +1705,7 @@ alpha_software_single_step (struct regcache *regcache)
}
-/* Initialize the current architecture based on INFO. If possible, re-use an
+/* Initialize the current architecture based on INFO. If possible, reuse an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c
index 6ce7c45..613f275 100644
--- a/gdb/amd64-fbsd-nat.c
+++ b/gdb/amd64-fbsd-nat.c
@@ -137,7 +137,7 @@ amd64_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
/* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
Instead, the earlier register sets return early if the request
- was for a specific register that was already satisified to avoid
+ was for a specific register that was already satisfied to avoid
fetching the FPU/XSAVE state unnecessarily. */
#ifdef PT_GETXSTATE_INFO
@@ -214,7 +214,7 @@ amd64_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
/* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
Instead, the earlier register sets return early if the request
- was for a specific register that was already satisified to avoid
+ was for a specific register that was already satisfied to avoid
fetching the FPU/XSAVE state unnecessarily. */
#ifdef PT_GETXSTATE_INFO
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index e290d2c..a7868c3 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -412,7 +412,7 @@ amd64_canonicalize_syscall (enum amd64_syscall syscall_number)
case amd64_sys_mmap:
case amd64_x32_sys_mmap:
- return gdb_sys_mmap2;
+ return gdb_sys_old_mmap;
case amd64_sys_mprotect:
case amd64_x32_sys_mprotect:
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index bebfd0d..3c58b85 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -2608,7 +2608,7 @@ amd64_skip_xmm_prologue (CORE_ADDR pc, CORE_ADDR start_pc)
if (next_sal.line != start_pc_sal.line)
return pc;
- /* START_PC can be from overlayed memory, ignored here. */
+ /* START_PC can be from overlay memory, ignored here. */
if (target_read_code (next_sal.pc - 4, buf, sizeof (buf)) != 0)
return pc;
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index 7b4faac..1aa591a 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -714,7 +714,7 @@ struct arm_linux_hw_breakpoint
The Linux ptrace interface to hardware break-/watch-points presents the
values in a vector centred around 0 (which is used fo generic information).
- Positive indicies refer to breakpoint addresses/control registers, negative
+ Positive indices refer to breakpoint addresses/control registers, negative
indices to watchpoint addresses/control registers.
The Linux vector is indexed as follows:
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 858705e..53c8a05 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -1361,8 +1361,8 @@ arm_canonicalize_syscall (int syscall)
case 86: return gdb_sys_uselib;
case 87: return gdb_sys_swapon;
case 88: return gdb_sys_reboot;
- case 89: return gdb_old_readdir;
- case 90: return gdb_old_mmap;
+ case 89: return gdb_sys_old_readdir;
+ case 90: return gdb_sys_old_mmap;
case 91: return gdb_sys_munmap;
case 92: return gdb_sys_truncate;
case 93: return gdb_sys_ftruncate;
diff --git a/gdb/arm-pikeos-tdep.c b/gdb/arm-pikeos-tdep.c
index 4760755..b2c93bd 100644
--- a/gdb/arm-pikeos-tdep.c
+++ b/gdb/arm-pikeos-tdep.c
@@ -36,8 +36,6 @@ arm_pikeos_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
static enum gdb_osabi
arm_pikeos_osabi_sniffer (bfd *abfd)
{
- long number_of_symbols;
- long i;
int pikeos_stack_found = 0;
int pikeos_stack_size_found = 0;
@@ -50,20 +48,15 @@ arm_pikeos_osabi_sniffer (bfd *abfd)
OS ABI sniffers are called before the minimal symtabs are
created. So inspect the symbol table using BFD. */
- long storage_needed = bfd_get_symtab_upper_bound (abfd);
- if (storage_needed <= 0)
- return GDB_OSABI_UNKNOWN;
-
- gdb::unique_xmalloc_ptr<asymbol *> symbol_table
- ((asymbol **) xmalloc (storage_needed));
- number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table.get ());
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (abfd, false);
- if (number_of_symbols <= 0)
+ if (symbol_table.empty ())
return GDB_OSABI_UNKNOWN;
- for (i = 0; i < number_of_symbols; i++)
+ for (const asymbol *sym : symbol_table)
{
- const char *name = bfd_asymbol_name (symbol_table.get ()[i]);
+ const char *name = bfd_asymbol_name (sym);
if (strcmp (name, "_vm_stack") == 0
|| strcmp (name, "__p4_stack") == 0)
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 879f5cf..b985ca8 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -9202,7 +9202,7 @@ arm_store_return_value (struct type *type, struct regcache *regs,
{
/* Integral values greater than one word are stored in consecutive
registers starting with r0. This will always be a multiple of
- the regiser size. */
+ the register size. */
int len = type->length ();
int regno = ARM_A1_REGNUM;
@@ -10103,7 +10103,7 @@ arm_get_pc_address_flags (const frame_info_ptr &frame, CORE_ADDR pc)
}
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called e.g. at program startup, when reading a core file, and when
diff --git a/gdb/bcache.c b/gdb/bcache.c
index a9aab28..fe2c76d 100644
--- a/gdb/bcache.c
+++ b/gdb/bcache.c
@@ -250,7 +250,7 @@ print_percentage (int portion, int total)
}
-/* Print statistics on BCACHE's memory usage and efficacity at
+/* Print statistics on BCACHE's memory usage and efficacy at
eliminating duplication. NAME should describe the kind of data
BCACHE holds. Statistics are printed using `gdb_printf' and
its ilk. */
diff --git a/gdb/bcache.h b/gdb/bcache.h
index 82cdd13..2e05a15 100644
--- a/gdb/bcache.h
+++ b/gdb/bcache.h
@@ -173,7 +173,7 @@ struct bcache
added);
}
- /* Print statistics on this bcache's memory usage and efficacity at
+ /* Print statistics on this bcache's memory usage and efficacy at
eliminating duplication. TYPE should be a string describing the
kind of data this bcache holds. Statistics are printed using
`gdb_printf' and its ilk. */
diff --git a/gdb/bfin-tdep.c b/gdb/bfin-tdep.c
index 78ade80..f8294ed 100644
--- a/gdb/bfin-tdep.c
+++ b/gdb/bfin-tdep.c
@@ -769,7 +769,7 @@ bfin_abi (struct gdbarch *gdbarch)
}
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called e.g. at program startup, when reading a core file, and when
diff --git a/gdb/bpf-tdep.c b/gdb/bpf-tdep.c
index 8f3e50d..41c9738 100644
--- a/gdb/bpf-tdep.c
+++ b/gdb/bpf-tdep.c
@@ -307,7 +307,7 @@ bpf_return_value (struct gdbarch *gdbarch, struct value *function,
}
-/* Initialize the current architecture based on INFO. If possible, re-use an
+/* Initialize the current architecture based on INFO. If possible, reuse an
architecture from ARCHES, which is a list of architectures already created
during this debugging session. */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 3085ca1..0fb6fd9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1535,6 +1535,11 @@ void
breakpoint_set_commands (struct breakpoint *b,
counted_command_line &&commands)
{
+ /* If the commands have not changed then there's no need to update
+ anything, and no need to emit a breakpoint modified event. */
+ if (commands_equal (b->commands.get (), commands.get ()))
+ return;
+
validate_commands_for_breakpoint (b, commands.get ());
b->commands = std::move (commands);
@@ -3099,7 +3104,6 @@ insert_bp_location (struct bp_location *bl,
|| shared_objfile_contains_address_p (bl->pspace,
bl->address)))
{
- /* See also: disable_breakpoints_in_shlibs. */
bl->shlib_disabled = 1;
notify_breakpoint_modified (bl->owner);
if (!*disabled_breaks)
@@ -8079,44 +8083,19 @@ create_and_insert_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR add
return b;
}
-/* See breakpoint.h. */
-
-void
-disable_breakpoints_in_shlibs (program_space *pspace)
-{
- for (bp_location *loc : all_bp_locations ())
- {
- /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
- struct breakpoint *b = loc->owner;
-
- /* We apply the check to all breakpoints, including disabled for
- those with loc->duplicate set. This is so that when breakpoint
- becomes enabled, or the duplicate is removed, gdb will try to
- insert all breakpoints. If we don't set shlib_disabled here,
- we'll try to insert those breakpoints and fail. */
- if (((b->type == bp_jit_event)
- || is_breakpoint (b)
- || is_tracepoint (b))
- && loc->pspace == pspace
- && !loc->shlib_disabled
- && solib_name_from_address (loc->pspace, loc->address)
- )
- {
- loc->shlib_disabled = 1;
- }
- }
-}
-
/* Disable any breakpoints and tracepoints that are in SOLIB upon
notification of unloaded_shlib. Only apply to enabled breakpoints,
disabled ones can just stay disabled.
When STILL_IN_USE is true, SOLIB hasn't really been unmapped from
- the inferior. In this case, don't disable anything. */
+ the inferior. In this case, don't disable anything.
+
+ When SILENT is false notify the user if any breakpoints are disabled,
+ otherwise, still disable the breakpoints, but don't tell the user. */
static void
disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib,
- bool still_in_use)
+ bool still_in_use, bool silent)
{
if (still_in_use)
return;
@@ -8160,7 +8139,7 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib
bp_modified = true;
- if (!disabled_shlib_breaks && user_breakpoint_p (&b))
+ if (!disabled_shlib_breaks && !silent && user_breakpoint_p (&b))
{
target_terminal::ours_for_output ();
warning (_("Temporarily disabling breakpoints "
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 94fba1c..ec3a128 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1740,7 +1740,7 @@ extern void disable_overlay_breakpoints (void);
extern void set_std_terminate_breakpoint (void);
extern void delete_std_terminate_breakpoint (void);
-/* These functions respectively disable or reenable all currently
+/* These functions respectively disable or re-enable all currently
enabled watchpoints. When disabled, the watchpoints are marked
call_disabled. When re-enabled, they are marked enabled.
diff --git a/gdb/bsd-uthread.c b/gdb/bsd-uthread.c
index 67db0ca..129e7a6 100644
--- a/gdb/bsd-uthread.c
+++ b/gdb/bsd-uthread.c
@@ -295,7 +295,7 @@ bsd_uthread_solib_loaded (solib &so)
static void
bsd_uthread_solib_unloaded (program_space *pspace, const solib &so,
- bool still_in_use)
+ bool still_in_use, bool /* silent */)
{
if (bsd_uthread_solib_name.empty () || still_in_use)
return;
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 152f6f2..4a056d2 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1531,23 +1531,23 @@ handle_pt_insn_events (struct btrace_thread_info *btinfo,
if (event.variant.vmexit.has_vmxr != 0)
{
- std::string seperator = aux_string.back () == ':' ? "" : ",";
- aux_string += seperator + std::string (" vmxr = ")
+ std::string separator = aux_string.back () == ':' ? "" : ",";
+ aux_string += separator + std::string (" vmxr = ")
+ hex_string (event.variant.vmexit.vmxr);
}
if (event.variant.vmexit.has_vmxq != 0)
{
- std::string seperator = aux_string.back () == ':' ? "" : ",";
- aux_string += seperator + std::string (" vmxq = ")
+ std::string separator = aux_string.back () == ':' ? "" : ",";
+ aux_string += separator + std::string (" vmxq = ")
+ hex_string (event.variant.vmexit.vmxq);
}
if (event.ip_suppressed == 0)
{
pc = event.variant.vmexit.ip;
- std::string seperator = aux_string.back () == ':' ? "" : ",";
- aux_string += seperator + std::string (" ip = ")
+ std::string separator = aux_string.back () == ':' ? "" : ",";
+ aux_string += separator + std::string (" ip = ")
+ hex_string (*pc);
}
@@ -2136,7 +2136,7 @@ btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
/* Adjust the block trace in order to stitch old and new trace together.
BTRACE is the new delta trace between the last and the current stop.
TP is the traced thread.
- May modifx BTRACE as well as the existing trace in TP.
+ May modify BTRACE as well as the existing trace in TP.
Return 0 on success, -1 otherwise. */
static int
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 1d30f55..49e44a8 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -55,7 +55,7 @@ struct subfile
struct subfile *next = nullptr;
std::string name;
- /* This field is analoguous in function to symtab::filename_for_id.
+ /* This field is analogous in function to symtab::filename_for_id.
It is used to look up existing subfiles in calls to start_subfile. */
std::string name_for_id;
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index c28493f..5592234 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -807,22 +807,6 @@ public:
}
/* See language.h. */
- std::unique_ptr<compile_instance> get_compile_instance () const override
- {
- return c_get_compile_context ();
- }
-
- /* See language.h. */
- std::string compute_program (compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc) const override
- {
- return c_compute_program (inst, input, gdbarch, expr_block, expr_pc);
- }
-
- /* See language.h. */
bool can_print_type_offsets () const override
{
@@ -943,22 +927,6 @@ public:
}
/* See language.h. */
- std::unique_ptr<compile_instance> get_compile_instance () const override
- {
- return cplus_get_compile_context ();
- }
-
- /* See language.h. */
- std::string compute_program (compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc) const override
- {
- return cplus_compute_program (inst, input, gdbarch, expr_block, expr_pc);
- }
-
- /* See language.h. */
unsigned int search_name_hash (const char *name) const override
{
return cp_search_name_hash (name);
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index 0e733d8..06b7ad0 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -25,7 +25,6 @@ struct ui_file;
struct language_arch_info;
struct type_print_options;
struct parser_state;
-struct compile_instance;
#include "compile/compile.h"
#include "value.h"
@@ -132,43 +131,6 @@ extern bool c_is_string_type_p (struct type *type);
extern int c_textual_element_type (struct type *, char);
-/* Create a new instance of the C compiler and return it. This
- function never returns NULL, but rather throws an exception on
- failure. This is suitable for use as the
- language_defn::get_compile_instance method. */
-
-extern std::unique_ptr<compile_instance> c_get_compile_context ();
-
-/* Create a new instance of the C++ compiler and return it. This
- function never returns NULL, but rather throws an exception on
- failure. This is suitable for use as the
- language_defn::get_compile_instance method. */
-
-extern std::unique_ptr<compile_instance> cplus_get_compile_context ();
-
-/* This takes the user-supplied text and returns a new bit of code to
- compile.
-
- This is used as the compute_program language method; see that
- for a description of the arguments. */
-
-extern std::string c_compute_program (compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc);
-
-/* This takes the user-supplied text and returns a new bit of code to compile.
-
- This is used as the compute_program language method; see that
- for a description of the arguments. */
-
-extern std::string cplus_compute_program (compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc);
-
/* Return the canonical form of the C symbol NAME. If NAME is already
canonical, return nullptr. */
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 5decf3b..0337d01 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -660,9 +660,13 @@ execute_control_command_1 (struct command_line *cmd, int from_tty)
}
case compile_control:
+#if defined(HAVE_COMPILE)
eval_compile_command (cmd, NULL, cmd->control_u.compile.scope,
cmd->control_u.compile.scope_data);
ret = simple_control;
+#else
+ error (_("compile support has not been compiled into gdb"));
+#endif
break;
case define_control:
@@ -1621,6 +1625,65 @@ define_prefix_command (const char *comname, int from_tty)
c->allow_unknown = c->user_commands.get () != nullptr;
}
+/* See cli/cli-script.h. */
+
+bool
+commands_equal (const command_line *a, const command_line *b)
+{
+ if ((a == nullptr) != (b == nullptr))
+ return false;
+
+ while (a != nullptr)
+ {
+ /* We are either at the end of both command lists, or there's
+ another command in both lists. */
+ if ((a->next == nullptr) != (b->next == nullptr))
+ return false;
+
+ /* There's a command line for both, or neither. */
+ if ((a->line == nullptr) != (b->line == nullptr))
+ return false;
+
+ /* Check control_type matches. */
+ if (a->control_type != b->control_type)
+ return false;
+
+ if (a->control_type == compile_control)
+ {
+ if (a->control_u.compile.scope != b->control_u.compile.scope)
+ return false;
+
+ /* This is where we "fail safe". The scope_data is a 'void *'
+ pointer which changes in meaning based on the value of
+ 'scope'. It is possible that two different 'void *' pointers
+ could point to the equal scope data, however, we just assume
+ that if the pointers are different, then the scope_data is
+ different. This could be improved in the future. */
+ if (a->control_u.compile.scope_data
+ != b->control_u.compile.scope_data)
+ return false;
+ }
+
+ /* Check lines are identical. */
+ if (a->line != nullptr && strcmp (a->line, b->line) != 0)
+ return false;
+
+ /* Check body_list_0. */
+ if (!commands_equal (a->body_list_0.get (), b->body_list_0.get ()))
+ return false;
+
+ /* Check body_list_1. */
+ if (!commands_equal (a->body_list_1.get (), b->body_list_1.get ()))
+ return false;
+
+ /* Move to the next element in each chain. */
+ a = a->next;
+ b = b->next;
+ }
+
+ return true;
+}
+
/* Used to implement source_command. */
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index df7316e..23a1e1f 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -184,4 +184,14 @@ extern void print_command_trace (const char *cmd, ...)
extern void reset_command_nest_depth (void);
+/* Return true if A and B are identical. Some commands carry around a
+ 'void *' compilation context, in this case this function doesn't try to
+ validate if the context is actually the same or not, and will just
+ return false indicating the commands have changed. That is, a return
+ value of true is a guarantee that the commands are equal, a return
+ value of false means the commands are possibly different (and in most
+ cases are different). */
+
+extern bool commands_equal (const command_line *a, const command_line *b);
+
#endif /* GDB_CLI_CLI_SCRIPT_H */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index c470668..e580f8c 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -903,7 +903,7 @@ coff_symtab_read (minimal_symbol_reader &reader,
symnum = 0;
while (symnum < nsyms)
{
- QUIT; /* Make this command interruptable. */
+ QUIT; /* Make this command interruptible. */
read_one_sym (cs, &main_sym, &main_aux);
diff --git a/gdb/command.h b/gdb/command.h
index 37c7ddf..7e6761d 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -558,7 +558,7 @@ extern struct cmd_list_element *lookup_cmd (const char **,
the section of text it matched, set *RESULT_LIST to point to the list in
which the last word was matched, and will return a pointer to the cmd
list element which the text matches. It will return NULL if no match at
- all was possible. It will return -1 (cast appropriately, ick) if ambigous
+ all was possible. It will return -1 (cast appropriately, ick) if ambiguous
matches are possible; in this case *RESULT_LIST will be set to point to
the list in which there are ambiguous choices (and *TEXT will be set to
the ambiguous text string).
diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
index f4cc9ee..789782d 100644
--- a/gdb/compile/compile-internal.h
+++ b/gdb/compile/compile-internal.h
@@ -80,4 +80,43 @@ private:
std::string m_object_file;
};
+struct compile_instance;
+
+/* Create a new instance of the C compiler and return it. This
+ function never returns NULL, but rather throws an exception on
+ failure. This is suitable for use as the
+ language_defn::get_compile_instance method. */
+
+extern std::unique_ptr<compile_instance> c_get_compile_context ();
+
+/* Create a new instance of the C++ compiler and return it. This
+ function never returns NULL, but rather throws an exception on
+ failure. This is suitable for use as the
+ language_defn::get_compile_instance method. */
+
+extern std::unique_ptr<compile_instance> cplus_get_compile_context ();
+
+/* This takes the user-supplied text and returns a new bit of code to
+ compile.
+
+ This is used as the compute_program language method; see that
+ for a description of the arguments. */
+
+extern std::string c_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc);
+
+/* This takes the user-supplied text and returns a new bit of code to compile.
+
+ This is used as the compute_program language method; see that
+ for a description of the arguments. */
+
+extern std::string cplus_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc);
+
#endif /* GDB_COMPILE_COMPILE_INTERNAL_H */
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index ef77ee3..05e5b43 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -605,9 +605,7 @@ compile_object_load (const compile_file_names &file_names,
CORE_ADDR regs_addr, out_value_addr = 0;
struct symbol *func_sym;
struct type *func_type;
- long storage_needed;
- asymbol **symbol_table, **symp;
- long number_of_symbols, missing_symbols;
+ long missing_symbols;
struct type *regs_type, *out_value_type = NULL;
char **matching;
struct objfile *objfile;
@@ -635,11 +633,6 @@ compile_object_load (const compile_file_names &file_names,
setup_sections_data.setup_one_section (sect);
setup_sections_data.setup_one_section (nullptr);
- storage_needed = bfd_get_symtab_upper_bound (abfd.get ());
- if (storage_needed < 0)
- error (_("Cannot read symbols of compiled module \"%s\": %s"),
- filename.get (), bfd_errmsg (bfd_get_error ()));
-
/* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in
"Reading symbols from ..." message for automatically generated file. */
scoped_objfile_unlinker objfile_holder (symbol_file_add_from_bfd
@@ -692,21 +685,12 @@ compile_object_load (const compile_file_names &file_names,
"module \"%s\"."),
GCC_FE_WRAPPER_FUNCTION, objfile_name (objfile));
- /* The memory may be later needed
- by bfd_generic_get_relocated_section_contents
- called from default_symfile_relocate. */
- symbol_table = (asymbol **) obstack_alloc (&objfile->objfile_obstack,
- storage_needed);
- number_of_symbols = bfd_canonicalize_symtab (abfd.get (), symbol_table);
- if (number_of_symbols < 0)
- error (_("Cannot parse symbols of compiled module \"%s\": %s"),
- filename.get (), bfd_errmsg (bfd_get_error ()));
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (abfd.get ());
missing_symbols = 0;
- for (symp = symbol_table; symp < symbol_table + number_of_symbols; symp++)
+ for (asymbol *sym : symbol_table)
{
- asymbol *sym = *symp;
-
if (sym->flags != 0)
continue;
sym->flags = BSF_GLOBAL;
@@ -800,7 +784,7 @@ compile_object_load (const compile_file_names &file_names,
if (missing_symbols)
error (_("%ld symbols were missing, cannot continue."), missing_symbols);
- bfd_map_over_sections (abfd.get (), copy_sections, symbol_table);
+ bfd_map_over_sections (abfd.get (), copy_sections, symbol_table.data ());
regs_type = get_regs_type (func_sym, objfile);
if (regs_type == NULL)
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index d6bcc1f..01f43ad 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -46,16 +46,17 @@
#include "gdbsupport/scoped_ignore_signal.h"
#include "gdbsupport/buildargv.h"
+/* Hold "compile" commands. */
+
+static struct cmd_list_element *compile_command_list;
+
+#ifdef HAVE_COMPILE
/* Initial filename for temporary files. */
#define TMP_PREFIX "/tmp/gdbobj-"
-/* Hold "compile" commands. */
-
-static struct cmd_list_element *compile_command_list;
-
/* Debug flag for "compile" commands. */
bool compile_debug;
@@ -527,6 +528,41 @@ print_callback (void *ignore, const char *message)
gdb_puts (message, gdb_stderr);
}
+/* Helper for compile_to_object, to find the compile context
+ based on the current language. */
+static std::unique_ptr<compile_instance>
+get_language_compile_context ()
+{
+ switch (current_language->la_language)
+ {
+ case language_c:
+ return c_get_compile_context ();
+ case language_cplus:
+ return cplus_get_compile_context ();
+ default:
+ return {};
+ }
+}
+
+/* Helper for compile_to_object, to call the correct
+ compute_program based on the current language. */
+static std::string
+compute_program_language (compile_instance *inst, const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *block,
+ CORE_ADDR pc)
+{
+ switch (current_language->la_language)
+ {
+ case language_c:
+ return c_compute_program (inst, input, gdbarch, block, pc);
+ case language_cplus:
+ return cplus_compute_program (inst, input, gdbarch, block, pc);
+ default:
+ gdb_assert_not_reached ("Unsupported language");
+ }
+}
+
/* Process the compilation request. On success it returns the object
and source file names. On an error condition, error () is
called. */
@@ -550,7 +586,8 @@ compile_to_object (struct command_line *cmd, const char *cmd_string,
/* Set up instance and context for the compiler. */
std::unique_ptr<compile_instance> compiler
- = current_language->get_compile_instance ();
+ = get_language_compile_context ();
+
if (compiler == nullptr)
error (_("No compiler support for language %s."),
current_language->name ());
@@ -582,8 +619,8 @@ compile_to_object (struct command_line *cmd, const char *cmd_string,
error (_("Neither a simple expression, or a multi-line specified."));
std::string code
- = current_language->compute_program (compiler.get (), input, gdbarch,
- expr_block, expr_pc);
+ = compute_program_language (compiler.get (), input, gdbarch,
+ expr_block, expr_pc);
if (compile_debug)
gdb_printf (gdb_stdlog, "debug output:\n\n%s", code.c_str ());
@@ -816,6 +853,18 @@ compile_instance::compile (const char *filename, int verbose_level)
#undef FORWARD
+#else /* HAVE_COMPILE */
+
+/* The "compile" prefix command, when support was disabled. */
+
+static void
+compile_command (const char *args, int from_tty)
+{
+ error (_("This command is not supported."));
+}
+
+#endif /* HAVE_COMPILE */
+
/* See compile.h. */
cmd_list_element *compile_cmd_element = nullptr;
@@ -823,14 +872,25 @@ void _initialize_compile ();
void
_initialize_compile ()
{
- struct cmd_list_element *c = NULL;
-
compile_cmd_element = add_prefix_cmd ("compile", class_obscure,
- compile_command, _("\
+ compile_command,
+#ifdef HAVE_COMPILE
+ _("\
Command to compile source code and inject it into the inferior."),
+#else /* HAVE_COMPILE */
+ _("\
+Command to compile source code and inject it into the inferior.\n\
+\n\
+Code compilation and injection is not supported in this copy of GDB.\n\
+This command is only a placeholder."),
+#endif /* HAVE_COMPILE */
&compile_command_list, 1, &cmdlist);
add_com_alias ("expression", compile_cmd_element, class_obscure, 0);
+#ifdef HAVE_COMPILE
+
+ struct cmd_list_element *c = NULL;
+
const auto compile_opts = make_compile_options_def_group (nullptr);
static const std::string compile_code_help
@@ -937,4 +997,5 @@ It should be absolute filename of the gcc executable.\n\
If empty the default target triplet will be searched in $PATH."),
NULL, show_compile_gcc, &setlist,
&showlist);
+#endif /* HAVE_COMPILE */
}
diff --git a/gdb/completer.c b/gdb/completer.c
index 4735aa5..0a8409b 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -356,7 +356,7 @@ gdb_completer_file_name_quote_1 (const char *text, char quote_char)
if (quote_char == '\'')
{
/* There is no backslash escaping permitted within a single quoted
- string, so in this case we can just return the input sting. */
+ string, so in this case we can just return the input string. */
str = text;
}
else if (quote_char == '"')
diff --git a/gdb/completer.h b/gdb/completer.h
index 07953f1..22d85a8 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -722,7 +722,7 @@ extern void complete_nested_command_line (completion_tracker &tracker,
This function is designed so that trying to complete '/' will offer no
completions, the user needs to insert the format specification
themselves. Trying to complete '/FMT' (where FMT is any non-empty set
- of alpha-numeric characters) will cause readline to insert a single
+ of alphanumeric characters) will cause readline to insert a single
space, setting the user up to enter the expression. */
extern bool skip_over_slash_fmt (completion_tracker &tracker,
diff --git a/gdb/config.in b/gdb/config.in
index db63aea..86ff67d 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -104,6 +104,9 @@
the CoreFoundation framework. */
#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+/* Define if compiling support to gdb compile. */
+#undef HAVE_COMPILE
+
/* Define to 1 if you have the <cursesX.h> header file. */
#undef HAVE_CURSESX_H
diff --git a/gdb/configure b/gdb/configure
index 3080413..e8a649f 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -956,6 +956,7 @@ with_libexpat_type
with_python
with_python_libdir
with_guile
+enable_gdb_compile
enable_source_highlight
with_sysroot
with_system_gdbinit
@@ -1650,6 +1651,8 @@ Optional Features:
--enable-gdbtk enable gdbtk graphical user interface (GUI)
--enable-profiling enable profiling of GDB
--enable-codesign=CERT sign gdb with 'codesign -s CERT'
+ --enable-gdb-compile enable support for the compile subsystem, default
+ 'yes'
--enable-source-highlight
enable source-highlight for source listings
--enable-werror treat compile warnings as errors
@@ -11500,7 +11503,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11503 "configure"
+#line 11506 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11606,7 +11609,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11609 "configure"
+#line 11612 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -28969,6 +28972,38 @@ fi
# ---------------------------- #
+# Check for compile support. #
+# ---------------------------- #
+
+# Check whether --enable-gdb-compile was given.
+if test "${enable_gdb_compile+set}" = set; then :
+ enableval=$enable_gdb_compile;
+ case $enableval in
+ yes | no)
+ ;;
+ *)
+ as_fn_error $? "bad value $enableval for --enable-gdb-compile" "$LINENO" 5
+ ;;
+ esac
+
+else
+ enable_gdb_compile=yes
+fi
+
+
+if test "${enable_gdb_compile}" == yes; then
+
+$as_echo "#define HAVE_COMPILE 1" >>confdefs.h
+
+ CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_GCC_COMPILE_OBS)"
+else
+ # Even if compile support is not enabled, we need this file to define
+ # the "compile" command.
+ CONFIG_OBS="$CONFIG_OBS compile/compile.o"
+ CONFIG_SRCS="$CONFIG_SRCS compile/compile.c"
+fi
+
+# ---------------------------- #
# Check for source highlight. #
# ---------------------------- #
diff --git a/gdb/configure.ac b/gdb/configure.ac
index eafbf5a..2411b10 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1222,6 +1222,26 @@ AC_SUBST(GUILE_LIBS)
AM_CONDITIONAL(HAVE_GUILE, test "${have_libguile}" != no)
# ---------------------------- #
+# Check for compile support. #
+# ---------------------------- #
+
+AC_ARG_ENABLE([gdb-compile],
+ AS_HELP_STRING([--enable-gdb-compile],
+ [enable support for the compile subsystem, default 'yes']),
+ [GDB_CHECK_YES_NO_VAL([$enableval], [--enable-gdb-compile])],
+ [enable_gdb_compile=yes])
+
+if test "${enable_gdb_compile}" == yes; then
+ AC_DEFINE(HAVE_COMPILE, 1, [Define if compiling support to gdb compile.])
+ CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_GCC_COMPILE_OBS)"
+else
+ # Even if compile support is not enabled, we need this file to define
+ # the "compile" command.
+ CONFIG_OBS="$CONFIG_OBS compile/compile.o"
+ CONFIG_SRCS="$CONFIG_SRCS compile/compile.c"
+fi
+
+# ---------------------------- #
# Check for source highlight. #
# ---------------------------- #
diff --git a/gdb/contrib/codespell-ignore-words.txt b/gdb/contrib/codespell-ignore-words.txt
index a8287f7..2d6e13a 100644
--- a/gdb/contrib/codespell-ignore-words.txt
+++ b/gdb/contrib/codespell-ignore-words.txt
@@ -1,3 +1,2 @@
configury
-invokable
-useable
+SME
diff --git a/gdb/contrib/common-misspellings.txt b/gdb/contrib/common-misspellings.txt
deleted file mode 100644
index 5772f66..0000000
--- a/gdb/contrib/common-misspellings.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 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 file contains additions to and overrides for
-# wikipedia-common-misspellings.txt.
-
-# Common spelling mistakes.
-
-inbetween->between, in between, in-between
-sofar->so far
-doens't->doesn't
-behavour->behavior
-behaviour->behavior
-arrithemetic->arithmetic
-electricaly->electrically
-
-# Identity rules.
-
-thru->thru
diff --git a/gdb/contrib/setup.cfg b/gdb/contrib/setup.cfg
new file mode 100644
index 0000000..dbff165
--- /dev/null
+++ b/gdb/contrib/setup.cfg
@@ -0,0 +1,6 @@
+[codespell]
+
+# Skip ChangeLogs and generated files.
+skip = */ChangeLog*,*/configure,gdbsupport/Makefile.in,*.dat,*.eps,gdb/features/*.c,gdb/ada-casefold.h,gdb/copying.c,gdb/gdbarch-gen.h,gdb/gdbarch-gen.c,gdb/target-delegates-gen.c
+
+ignore-words = gdb/contrib/codespell-ignore-words.txt
diff --git a/gdb/contrib/spellcheck.sh b/gdb/contrib/spellcheck.sh
deleted file mode 100755
index 420891f..0000000
--- a/gdb/contrib/spellcheck.sh
+++ /dev/null
@@ -1,536 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 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/>.
-
-# Script to auto-correct common spelling mistakes.
-#
-# Example usage:
-# $ ./gdb/contrib/spellcheck.sh gdb*
-
-scriptdir=$(cd "$(dirname "$0")" || exit; pwd -P)
-this_script=$scriptdir/$(basename "$0")
-
-url=https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines
-cache_dir=$scriptdir/../../.git
-cache_file=wikipedia-common-misspellings.txt
-dictionary=$cache_dir/$cache_file
-local_dictionary=$scriptdir/common-misspellings.txt
-cache_file2=spell-check.pat1
-
-bash_version_at_least ()
-{
- local major
- major="$1"
- local minor
- minor="$2"
-
- if [ "$bash_major" = "" ]; then
- bash_major=$(echo "$BASH_VERSION" | awk -F '.' '{print $1}')
- bash_minor=$(echo "$BASH_VERSION" | awk -F '.' '{print $2}')
- fi
-
- if [ "$bash_major" -lt "$major" ]; then
- # Major version less then required, return false.
- return 1
- fi
-
- if [ "$bash_major" -gt "$major" ]; then
- # Major version more then required, return true.
- return 0
- fi
-
- # Check minor version.
- [ "$bash_minor" -ge "$minor" ]
-}
-
-# Separators: space, slash, tab, colon, comma.
-declare -a grep_separators
-grep_separators=(
- " "
- "/"
- " "
- ":"
- ","
- "\""
-)
-declare -a sed_separators
-sed_separators=(
- " "
- "/"
- "\t"
- ":"
- ","
- "\""
-)
-
-# Pre: start of line, left parenthesis.
-declare -a grep_pre
-grep_pre=(
- "^"
- "\("
-)
-declare -a sed_pre
-sed_pre=(
- "^"
- "("
-)
-
-# Post: dot, right parenthesis, end of line.
-declare -a grep_post
-grep_post=(
- "\."
- "\)"
- "$"
-)
-declare -a sed_post
-sed_post=(
- "\."
- ")"
- "$"
-)
-
-join ()
-{
- local or
- or="$1"
- shift
-
- local res
- res=""
-
- local first
- first=true
-
- for item in "$@"; do
- if $first; then
- first=false
- res="$item"
- else
- res="$res$or$item"
- fi
- done
-
- echo "$res"
-}
-
-grep_or="|"
-sed_or="\|"
-
-grep_join ()
-{
- local res
- res=$(join $grep_or "$@")
- echo "($res)"
-}
-
-sed_join ()
-{
- local res
- res=$(join $sed_or "$@")
- echo "\($res\)"
-}
-
-usage ()
-{
- echo "usage: $(basename "$0") [--check] <file|dir>+"
- echo " $(basename "$0") --print-dictionary"
-}
-
-make_absolute ()
-{
- local arg
- arg="$1"
-
- case "$arg" in
- /*)
- ;;
- *)
- arg=$(pwd -P)/"$arg"
- ;;
- esac
-
- echo "$arg"
-}
-
-parse_args ()
-{
- local files
- files=$(mktemp)
- trap 'rm -f "$files"' EXIT
-
- if [ $# -eq 1 ] && [ "$1" = "--print-dictionary" ]; then
- print_dictionary=true
- return
- fi
-
- while true; do
- case " $1 " in
- " --check ")
- check=true
- shift
- ;;
- *)
- break
- ;;
- esac
- done
-
- if [ $# -eq -0 ]; then
- usage
- exit 1
- fi
-
- local arg
- for arg in "$@"; do
- if [ -f "$arg" ]; then
- arg=$(make_absolute "$arg")
- readlink -e "$arg" \
- >> "$files"
- elif [ -d "$arg" ]; then
- arg=$(make_absolute "$arg")
- local f
- find "$arg" -type f -exec readlink -e {} \; \
- >> "$files"
- else
- echo "Not a file or directory: $arg"
- exit 1
- fi
- done
-
- mapfile -t unique_files \
- < <(sort -u "$files" \
- | grep -v ChangeLog)
-
- rm -f "$files"
- trap "" EXIT
-}
-
-get_dictionary ()
-{
- if [ -f "$dictionary" ]; then
- return
- fi
-
- local webpage
- webpage=$(mktemp)
- trap 'rm -f "$webpage"' EXIT
-
- # Download web page containing table.
- wget $url -O "$webpage"
-
- # Extract table from web page.
- awk '/<pre>/,/<\/pre>/' "$webpage" \
- | sed 's/<pre>//;s/<\/pre>//' \
- | grep -E -v "^$" \
- > "$dictionary"
-
- rm -f "$webpage"
- trap "" EXIT
-}
-
-output_local_dictionary ()
-{
- # Filter out comments and empty lines.
- grep -E -v \
- "^#|^$" \
- "$local_dictionary"
-}
-
-output_dictionaries ()
-{
- (
- output_local_dictionary
- cat "$dictionary"
- ) | grep -E -v "[A-Z]"
-}
-
-parse_dictionary ()
-{
- # Parse dictionary.
- mapfile -t words \
- < <(awk -F '->' '{print $1}' <(output_dictionaries))
- mapfile -t replacements \
- < <(awk -F '->' '{print $2}' <(output_dictionaries))
-
- local words_done
- declare -A words_done
- local i word replacement
- i=0
- for word in "${words[@]}"; do
- replacement=${replacements[i]}
-
- # Skip words that are already handled. This ensures that the local
- # dictionary overrides the wiki dictionary.
- if [ "${words_done[$word]}" == 1 ]; then
- words[i]=""
- replacements[i]=""
- i=$((i + 1))
- continue
- fi
- words_done[$word]=1
-
- # Skip identity rules.
- if [ "$word" = "$replacement" ]; then
- words[i]=""
- replacements[i]=""
- fi
-
- i=$((i + 1))
- done
-}
-
-print_dictionary ()
-{
- local i word replacement
- i=0
- for word in "${words[@]}"; do
- replacement=${replacements[i]}
- i=$((i + 1))
-
- if [ "$word" == "" ]; then
- continue
- fi
-
- echo "$word -> $replacement"
- done
-}
-
-find_files_matching_words ()
-{
- local cache_id
- cache_id=$(cat "$local_dictionary" "$dictionary" "$this_script" \
- | md5sum \
- | awk '{print $1}')
-
- local patfile
- patfile="$cache_dir/$cache_file2".$cache_id
-
- local pat
- if [ -f "$patfile" ]; then
- pat=$(cat "$patfile")
- else
- rm -f "$cache_dir/$cache_file2".*
-
- declare -a re_words
- mapfile -t re_words \
- < <(for f in "${words[@]}"; do
- if [ "$f" = "" ]; then
- continue
- fi
- echo "$f"
- done \
- | sed "s/^\(.\)/[\u\1\1]/")
-
- pat=$(grep_join "${re_words[@]}")
-
- local before after
- before=$(grep_join \
- "${grep_pre[@]}" \
- "${grep_separators[@]}")
- after=$(grep_join \
- "${grep_separators[@]}" \
- "${grep_post[@]}")
-
- pat="$before$pat$after"
-
- echo "$pat" \
- > "$patfile"
- fi
-
- grep -E \
- -l \
- "$pat" \
- "$@"
-}
-
-find_files_matching_word ()
-{
- local pat
- pat="$1"
- shift
-
- local before after
- before=$(grep_join \
- "${grep_pre[@]}" \
- "${grep_separators[@]}")
- after=$(grep_join \
- "${grep_separators[@]}" \
- "${grep_post[@]}")
-
- if bash_version_at_least 5 1; then
- patc=${pat@u}
- else
- # shellcheck disable=SC2001
- patc=$(echo "$pat" | sed 's/^\(.\)/\u\1/')
- fi
- pat="($patc|$pat)"
-
- pat="$before$pat$after"
-
- grep -E \
- -l \
- "$pat" \
- "$@"
-}
-
-replace_word_in_file ()
-{
- local word
- word="$1"
-
- local replacement
- replacement="$2"
-
- local file
- file="$3"
-
- local before after
- before=$(sed_join \
- "${sed_pre[@]}" \
- "${sed_separators[@]}")
- after=$(sed_join \
- "${sed_separators[@]}" \
- "${sed_post[@]}")
-
- if bash_version_at_least 5 1; then
- wordc=${word@u}
- replacementc=${replacement@u}
- else
- # shellcheck disable=SC2001
- wordc=$(echo "$word" | sed 's/^\(.\)/\u\1/')
- # shellcheck disable=SC2001
- replacementc=$(echo "$replacement" | sed 's/^\(.\)/\u\1/')
- fi
-
- local repl1
- local repl2
- repl1="s%$before$word$after%\1$replacement\2%g"
- repl2="s%$before$wordc$after%\1$replacementc\2%g"
-
- sed -i \
- "$repl1;$repl2" \
- "$file"
-}
-
-replace_word_in_files ()
-{
- local word
- word="$1"
-
- local replacement
- replacement="$2"
-
- shift 2
-
- local id
- id="$word -> $replacement"
-
- # Reduce set of files for sed to operate on.
- local files_matching_word
- declare -a files_matching_word
- mapfile -t files_matching_word \
- < <(find_files_matching_word "$word" "$@")
-
- if [ ${#files_matching_word[@]} -eq 0 ]; then
- return
- fi
-
- if echo "$replacement"| grep -q ","; then
- echo "TODO: $id"
- return
- fi
-
- declare -A md5sums
-
- local changed f before after
- changed=false
- for f in "${files_matching_word[@]}"; do
- if [ "${md5sums[$f]}" = "" ]; then
- md5sums[$f]=$(md5sum "$f")
- fi
-
- before="${md5sums[$f]}"
-
- replace_word_in_file \
- "$word" \
- "$replacement" \
- "$f"
-
- after=$(md5sum "$f")
-
- if [ "$after" != "$before" ]; then
- md5sums[$f]="$after"
- changed=true
- fi
- done
-
- if $changed; then
- echo "$id"
- fi
-
- find_files_matching_word "$word" "${files_matching_word[@]}" \
- | awk "{ printf \"TODO: $id: replacement failed: %s\n\", \$0}"
-}
-
-main ()
-{
- declare -a unique_files
- check=false
- print_dictionary=false
- parse_args "$@"
-
- get_dictionary
-
- declare -a words
- declare -a replacements
- parse_dictionary
-
- if $print_dictionary; then
- print_dictionary
- exit 0
- fi
-
- # Reduce set of files for sed to operate on.
- local files_matching_words
- declare -a files_matching_words
- mapfile -t files_matching_words \
- < <(find_files_matching_words "${unique_files[@]}")
-
- if [ ${#files_matching_words[@]} -eq 0 ]; then
- return
- fi
-
- if $check; then
- exit 1
- fi
-
- local i word replacement
- i=0
- for word in "${words[@]}"; do
- replacement=${replacements[i]}
- i=$((i + 1))
-
- if [ "$word" = "" ]; then
- continue
- fi
-
- replace_word_in_files \
- "$word" \
- "$replacement" \
- "${files_matching_words[@]}"
- done
-}
-
-main "$@"
diff --git a/gdb/copyright.py b/gdb/copyright.py
index 1a155b9..5ec9944 100755
--- a/gdb/copyright.py
+++ b/gdb/copyright.py
@@ -1,6 +1,6 @@
#! /usr/bin/env python3
-# Copyright (C) 2011-2024 Free Software Foundation, Inc.
+# Copyright (C) 2011-2025 Free Software Foundation, Inc.
#
# This file is part of GDB.
#
@@ -20,7 +20,7 @@
# This script updates the list of years in the copyright notices in
# most files maintained by the GDB project.
#
-# Usage: cd src/gdb && ./copyright.py
+# Usage: ./gdb/copyright.py
#
# Always review the output of this script before committing it!
#
@@ -46,39 +46,41 @@ def get_update_list():
of the GDB source tree (NOT the gdb/ subdirectory!). The names of
the files are relative to that root directory.
"""
- result = []
- for gdb_dir in (
- "gdb",
- "gdbserver",
- "gdbsupport",
- "gnulib",
- "sim",
- "include/gdb",
- ):
- for root, dirs, files in os.walk(gdb_dir, topdown=True):
- for dirname in dirs:
- reldirname = "%s/%s" % (root, dirname)
- if (
- dirname in EXCLUDE_ALL_LIST
- or reldirname in EXCLUDE_LIST
- or reldirname in NOT_FSF_LIST
- or reldirname in BY_HAND
- ):
- # Prune this directory from our search list.
- dirs.remove(dirname)
- for filename in files:
- relpath = "%s/%s" % (root, filename)
- if (
- filename in EXCLUDE_ALL_LIST
- or relpath in EXCLUDE_LIST
- or relpath in NOT_FSF_LIST
- or relpath in BY_HAND
- ):
- # Ignore this file.
- pass
- else:
- result.append(relpath)
- return result
+ result = (
+ subprocess.check_output(
+ [
+ "git",
+ "ls-files",
+ "-z",
+ "--",
+ "gdb",
+ "gdbserver",
+ "gdbsupport",
+ "gnulib",
+ "sim",
+ "include/gdb",
+ ],
+ text=True,
+ )
+ .rstrip("\0")
+ .split("\0")
+ )
+
+ def include_file(filename):
+ (dirname, basename) = os.path.split(filename)
+ dirbasename = os.path.basename(dirname)
+ return not (
+ basename in EXCLUDE_ALL_LIST
+ or dirbasename in EXCLUDE_ALL_LIST
+ or dirname in EXCLUDE_LIST
+ or dirname in NOT_FSF_LIST
+ or dirname in BY_HAND
+ or filename in EXCLUDE_LIST
+ or filename in NOT_FSF_LIST
+ or filename in BY_HAND
+ )
+
+ return filter(include_file, result)
def update_files(update_list):
@@ -168,13 +170,9 @@ def main(argv: List[str]) -> Optional[int]:
"""The main subprogram."""
parser = get_parser()
_ = parser.parse_args(argv)
- root_dir = os.path.dirname(os.getcwd())
- os.chdir(root_dir)
- if not (
- os.path.isdir("gdb") and os.path.isfile("gnulib/import/extra/update-copyright")
- ):
- sys.exit("Error: This script must be called from the gdb directory.")
+ if not os.path.isfile("gnulib/import/extra/update-copyright"):
+ sys.exit("Error: This script must be called from the top-level directory.")
update_list = get_update_list()
update_files(update_list)
@@ -214,9 +212,11 @@ def main(argv: List[str]) -> Optional[int]:
#
# Filenames are relative to the root directory.
EXCLUDE_LIST = (
+ "gdb/copying.c",
"gdb/nat/glibc_thread_db.h",
"gdb/CONTRIBUTE",
"gdbsupport/Makefile.in",
+ "gdbsupport/unordered_dense.h",
"gnulib/doc/gendocs_template",
"gnulib/doc/gendocs_template_min",
"gnulib/import",
@@ -235,9 +235,7 @@ EXCLUDE_LIST = (
EXCLUDE_ALL_LIST = (
"COPYING",
"COPYING.LIB",
- "CVS",
"configure",
- "copying.c",
"fdl.texi",
"gpl.texi",
"aclocal.m4",
@@ -296,131 +294,7 @@ NOT_FSF_LIST = (
"sim/mips/sim-main.c",
"sim/moxie/moxie-gdb.dts",
# Not a single file in sim/ppc/ appears to be copyright FSF :-(.
- "sim/ppc/filter.h",
- "sim/ppc/gen-support.h",
- "sim/ppc/ld-insn.h",
- "sim/ppc/hw_sem.c",
- "sim/ppc/hw_disk.c",
- "sim/ppc/idecode_branch.h",
- "sim/ppc/sim-endian.h",
- "sim/ppc/table.c",
- "sim/ppc/hw_core.c",
- "sim/ppc/gen-support.c",
- "sim/ppc/gen-semantics.h",
- "sim/ppc/cpu.h",
- "sim/ppc/sim_callbacks.h",
- "sim/ppc/RUN",
- "sim/ppc/Makefile.in",
- "sim/ppc/emul_chirp.c",
- "sim/ppc/hw_nvram.c",
- "sim/ppc/dc-test.01",
- "sim/ppc/hw_phb.c",
- "sim/ppc/hw_eeprom.c",
- "sim/ppc/bits.h",
- "sim/ppc/hw_vm.c",
- "sim/ppc/cap.h",
- "sim/ppc/os_emul.h",
- "sim/ppc/options.h",
- "sim/ppc/gen-idecode.c",
- "sim/ppc/filter.c",
- "sim/ppc/corefile-n.h",
- "sim/ppc/std-config.h",
- "sim/ppc/ld-decode.h",
- "sim/ppc/filter_filename.h",
- "sim/ppc/hw_shm.c",
- "sim/ppc/pk_disklabel.c",
- "sim/ppc/dc-simple",
- "sim/ppc/misc.h",
- "sim/ppc/device_table.h",
- "sim/ppc/ld-insn.c",
- "sim/ppc/inline.c",
- "sim/ppc/emul_bugapi.h",
- "sim/ppc/hw_cpu.h",
- "sim/ppc/debug.h",
- "sim/ppc/hw_ide.c",
- "sim/ppc/debug.c",
- "sim/ppc/gen-itable.h",
- "sim/ppc/interrupts.c",
- "sim/ppc/hw_glue.c",
- "sim/ppc/emul_unix.c",
- "sim/ppc/sim_calls.c",
- "sim/ppc/dc-complex",
- "sim/ppc/ld-cache.c",
- "sim/ppc/registers.h",
- "sim/ppc/dc-test.02",
- "sim/ppc/options.c",
- "sim/ppc/igen.h",
- "sim/ppc/registers.c",
- "sim/ppc/device.h",
- "sim/ppc/emul_chirp.h",
- "sim/ppc/hw_register.c",
- "sim/ppc/hw_init.c",
- "sim/ppc/sim-endian-n.h",
- "sim/ppc/filter_filename.c",
- "sim/ppc/bits.c",
- "sim/ppc/idecode_fields.h",
- "sim/ppc/hw_memory.c",
- "sim/ppc/misc.c",
- "sim/ppc/double.c",
- "sim/ppc/psim.h",
- "sim/ppc/hw_trace.c",
- "sim/ppc/emul_netbsd.h",
- "sim/ppc/psim.c",
- "sim/ppc/powerpc.igen",
- "sim/ppc/tree.h",
- "sim/ppc/README",
- "sim/ppc/gen-icache.h",
- "sim/ppc/gen-model.h",
- "sim/ppc/ld-cache.h",
- "sim/ppc/mon.c",
- "sim/ppc/corefile.h",
- "sim/ppc/vm.c",
- "sim/ppc/INSTALL",
- "sim/ppc/gen-model.c",
- "sim/ppc/hw_cpu.c",
- "sim/ppc/corefile.c",
- "sim/ppc/hw_opic.c",
- "sim/ppc/gen-icache.c",
- "sim/ppc/events.h",
- "sim/ppc/os_emul.c",
- "sim/ppc/emul_generic.c",
- "sim/ppc/main.c",
- "sim/ppc/hw_com.c",
- "sim/ppc/gen-semantics.c",
- "sim/ppc/emul_bugapi.c",
- "sim/ppc/device.c",
- "sim/ppc/emul_generic.h",
- "sim/ppc/tree.c",
- "sim/ppc/mon.h",
- "sim/ppc/interrupts.h",
- "sim/ppc/cap.c",
- "sim/ppc/cpu.c",
- "sim/ppc/hw_phb.h",
- "sim/ppc/device_table.c",
- "sim/ppc/lf.c",
- "sim/ppc/lf.c",
- "sim/ppc/dc-stupid",
- "sim/ppc/hw_pal.c",
- "sim/ppc/ppc-spr-table",
- "sim/ppc/emul_unix.h",
- "sim/ppc/words.h",
- "sim/ppc/basics.h",
- "sim/ppc/hw_htab.c",
- "sim/ppc/lf.h",
- "sim/ppc/ld-decode.c",
- "sim/ppc/sim-endian.c",
- "sim/ppc/gen-itable.c",
- "sim/ppc/idecode_expression.h",
- "sim/ppc/table.h",
- "sim/ppc/dgen.c",
- "sim/ppc/events.c",
- "sim/ppc/gen-idecode.h",
- "sim/ppc/emul_netbsd.c",
- "sim/ppc/igen.c",
- "sim/ppc/vm_n.h",
- "sim/ppc/vm.h",
- "sim/ppc/hw_iobus.c",
- "sim/ppc/inline.h",
+ "sim/ppc",
"sim/testsuite/mips/mips32-dsp2.s",
)
diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index 370cb36..46cefc6 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -926,7 +926,7 @@ cp_lookup_nested_symbol (struct type *parent_type,
case TYPE_CODE_NAMESPACE:
case TYPE_CODE_UNION:
case TYPE_CODE_ENUM:
- /* NOTE: Handle modules here as well, because Fortran is re-using the C++
+ /* NOTE: Handle modules here as well, because Fortran is reusing the C++
specific code to lookup nested symbols in modules, by calling the
method lookup_symbol_nonlocal, which ends up here. */
case TYPE_CODE_MODULE:
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 2634c1e..2077fa3 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -100,7 +100,7 @@ cp_is_vtbl_member (struct type *type)
/* The type name of the thunk pointer is NULL when using
dwarf2. We could test for a pointer to a function, but
there is no type info for the virtual table either, so it
- wont help. */
+ won't help. */
return cp_is_vtbl_ptr_type (type);
}
}
diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
index f531b4c..519ea43 100644
--- a/gdb/cris-tdep.c
+++ b/gdb/cris-tdep.c
@@ -1467,7 +1467,7 @@ cris_register_size (struct gdbarch *gdbarch, int regno)
}
/* Nonzero if regno should not be fetched from the target. This is the case
- for unimplemented (size 0) and non-existant registers. */
+ for unimplemented (size 0) and non-existent registers. */
static int
cris_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
@@ -1508,7 +1508,7 @@ cris_cannot_store_register (struct gdbarch *gdbarch, int regno)
}
/* Nonzero if regno should not be fetched from the target. This is the case
- for unimplemented (size 0) and non-existant registers. */
+ for unimplemented (size 0) and non-existent registers. */
static int
crisv32_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
index 4f41a51..4f3d9d8 100644
--- a/gdb/csky-tdep.c
+++ b/gdb/csky-tdep.c
@@ -1072,7 +1072,7 @@ csky_analyze_prologue (struct gdbarch *gdbarch,
}
else if (CSKY_32_IS_MOV_FP_SP (insn))
{
- /* SP is saved to FP reg, means code afer prologue may
+ /* SP is saved to FP reg, means code after prologue may
modify SP. */
is_fp_saved = 1;
adjust_fp = stacksize;
@@ -2667,7 +2667,7 @@ csky_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
}
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called at program startup, when reading a core file, and when
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 287dc7f..c08a68d 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -97,6 +97,7 @@ PYTHON_FILE_LIST = \
gdb/command/xmethods.py \
gdb/dap/breakpoint.py \
gdb/dap/bt.py \
+ gdb/dap/completions.py \
gdb/dap/disassemble.py \
gdb/dap/evaluate.py \
gdb/dap/events.py \
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 86e59ab..9e2e572 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -31,36 +31,18 @@
for real. dbx_psymtab_to_symtab() is the function that does this */
-#include "event-top.h"
-#include "gdbsupport/gdb_obstack.h"
#include <sys/stat.h>
#include "symtab.h"
-#include "breakpoint.h"
#include "target.h"
-#include "gdbcore.h"
#include "libaout.h"
-#include "filenames.h"
#include "objfiles.h"
-#include "buildsym-legacy.h"
#include "stabsread.h"
#include "gdb-stabs.h"
-#include "demangle.h"
-#include "complaints.h"
-#include "cp-abi.h"
#include "cp-support.h"
-#include "c-lang.h"
-#include "psymtab.h"
-#include "block.h"
-#include "aout/aout64.h"
-#include "aout/stab_gnu.h"
-
+
/* Required for the following registry. */
#include "gdb-stabs.h"
-
-
-
-
/* Local function prototypes. */
static void dbx_symfile_init (struct objfile *);
diff --git a/gdb/dicos-tdep.c b/gdb/dicos-tdep.c
index 3627426..96b841a 100644
--- a/gdb/dicos-tdep.c
+++ b/gdb/dicos-tdep.c
@@ -53,9 +53,7 @@ dicos_init_abi (struct gdbarch *gdbarch)
int
dicos_load_module_p (bfd *abfd, int header_size)
{
- long storage_needed;
int ret = 0;
- asymbol **symbol_table = NULL;
const char *symname = "Dicos_loadModuleInfo";
asection *section;
@@ -75,42 +73,19 @@ dicos_load_module_p (bfd *abfd, int header_size)
/* Dicos LMs always have a "Dicos_loadModuleInfo" symbol
defined. Look for it. */
- storage_needed = bfd_get_symtab_upper_bound (abfd);
- if (storage_needed < 0)
- {
- warning (_("Can't read elf symbols from %s: %s"),
- bfd_get_filename (abfd),
- bfd_errmsg (bfd_get_error ()));
- return 0;
- }
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (abfd, false);
- if (storage_needed > 0)
+ for (asymbol *sym : symbol_table)
{
- long i, symcount;
-
- symbol_table = (asymbol **) xmalloc (storage_needed);
- symcount = bfd_canonicalize_symtab (abfd, symbol_table);
-
- if (symcount < 0)
- warning (_("Can't read elf symbols from %s: %s"),
- bfd_get_filename (abfd),
- bfd_errmsg (bfd_get_error ()));
- else
+ if (sym->name != NULL
+ && symname[0] == sym->name[0]
+ && strcmp (symname + 1, sym->name + 1) == 0)
{
- for (i = 0; i < symcount; i++)
- {
- asymbol *sym = symbol_table[i];
- if (sym->name != NULL
- && symname[0] == sym->name[0]
- && strcmp (symname + 1, sym->name + 1) == 0)
- {
- ret = 1;
- break;
- }
- }
+ ret = 1;
+ break;
}
}
- xfree (symbol_table);
return ret;
}
diff --git a/gdb/displaced-stepping.h b/gdb/displaced-stepping.h
index 7949e5d..2806107 100644
--- a/gdb/displaced-stepping.h
+++ b/gdb/displaced-stepping.h
@@ -246,7 +246,7 @@ private:
std::vector<displaced_step_buffer> m_buffers;
};
-/* Default implemention of target_ops::supports_displaced_step.
+/* Default implementation of target_ops::supports_displaced_step.
Forwards the call to the architecture of THREAD. */
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index ac1b1c5..a5bc9d8 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -424,7 +424,7 @@ dtrace_process_dof_probe (struct objfile *objfile,
It follows that if there are DTrace is-enabled probes defined for
some provider/name but no DTrace regular probes defined then the
- GDB user wont be able to enable/disable these conditionals. */
+ GDB user won't be able to enable/disable these conditionals. */
num_probes = DOF_UINT (dof, probe->dofpr_noffs);
if (num_probes == 0)
diff --git a/gdb/dwarf2/abbrev-table-cache.h b/gdb/dwarf2/abbrev-table-cache.h
index 8469948..d99fb8d 100644
--- a/gdb/dwarf2/abbrev-table-cache.h
+++ b/gdb/dwarf2/abbrev-table-cache.h
@@ -30,6 +30,9 @@ public:
abbrev_table_cache () = default;
DISABLE_COPY_AND_ASSIGN (abbrev_table_cache);
+ abbrev_table_cache (abbrev_table_cache &&) = default;
+ abbrev_table_cache &operator= (abbrev_table_cache &&) = default;
+
/* Find an abbrev table coming from the abbrev section SECTION at
offset OFFSET. Return the table, or nullptr if it has not yet
been registered. */
diff --git a/gdb/dwarf2/aranges.c b/gdb/dwarf2/aranges.c
index 7016eee..ac530ab 100644
--- a/gdb/dwarf2/aranges.c
+++ b/gdb/dwarf2/aranges.c
@@ -59,6 +59,7 @@ read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
gdb::unordered_set<sect_offset> debug_info_offset_seen;
const bfd_endian dwarf5_byte_order = gdbarch_byte_order (gdbarch);
+ const int signed_addr_p = bfd_get_sign_extend_vma (abfd);
const gdb_byte *addr = section->buffer;
while (addr < section->buffer + section->size)
{
@@ -167,8 +168,13 @@ read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
plongest (entry_addr - section->buffer));
return false;
}
- ULONGEST start = extract_unsigned_integer (addr, address_size,
- dwarf5_byte_order);
+ ULONGEST start;
+ if (signed_addr_p)
+ start = extract_signed_integer (addr, address_size,
+ dwarf5_byte_order);
+ else
+ start = extract_unsigned_integer (addr, address_size,
+ dwarf5_byte_order);
addr += address_size;
ULONGEST length = extract_unsigned_integer (addr, address_size,
dwarf5_byte_order);
diff --git a/gdb/dwarf2/cooked-index-entry.c b/gdb/dwarf2/cooked-index-entry.c
new file mode 100644
index 0000000..3e322f1
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-entry.c
@@ -0,0 +1,242 @@
+/* Entry in the cooked index
+
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "dwarf2/cooked-index-entry.h"
+#include "dwarf2/tag.h"
+#include "gdbsupport/gdb-safe-ctype.h"
+#include "gdbsupport/selftest.h"
+
+/* See cooked-index-entry.h. */
+
+std::string
+to_string (cooked_index_flag flags)
+{
+ static constexpr cooked_index_flag::string_mapping mapping[] = {
+ MAP_ENUM_FLAG (IS_MAIN),
+ MAP_ENUM_FLAG (IS_STATIC),
+ MAP_ENUM_FLAG (IS_LINKAGE),
+ MAP_ENUM_FLAG (IS_TYPE_DECLARATION),
+ MAP_ENUM_FLAG (IS_PARENT_DEFERRED),
+ };
+
+ return flags.to_string (mapping);
+}
+
+/* See cooked-index-entry.h. */
+
+int
+cooked_index_entry::compare (const char *stra, const char *strb,
+ comparison_mode mode)
+{
+#if defined (__GNUC__) && !defined (__clang__) && __GNUC__ <= 7
+ /* Work around error with gcc 7.5.0. */
+ auto munge = [] (char c) -> unsigned char
+#else
+ auto munge = [] (char c) constexpr -> unsigned char
+#endif
+ {
+ /* Treat '<' as if it ended the string. This lets something
+ like "func<t>" match "func<t<int>>". See the "Breakpoints in
+ template functions" section in the manual. */
+ if (c == '<')
+ return '\0';
+ return TOLOWER ((unsigned char) c);
+ };
+
+ unsigned char a = munge (*stra);
+ unsigned char b = munge (*strb);
+
+ while (a != '\0' && b != '\0' && a == b)
+ {
+ a = munge (*++stra);
+ b = munge (*++strb);
+ }
+
+ if (a == b)
+ return 0;
+
+ /* When completing, if STRB ends earlier than STRA, consider them as
+ equal. */
+ if (mode == COMPLETE && b == '\0')
+ return 0;
+
+ return a < b ? -1 : 1;
+}
+
+#if GDB_SELF_TEST
+
+namespace {
+
+void
+test_compare ()
+{
+ /* Convenience aliases. */
+ const auto mode_compare = cooked_index_entry::MATCH;
+ const auto mode_sort = cooked_index_entry::SORT;
+ const auto mode_complete = cooked_index_entry::COMPLETE;
+
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
+ mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
+ mode_compare) < 0);
+ SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
+ mode_compare) > 0);
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
+ mode_complete) < 0);
+ SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
+ mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
+ mode_complete) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
+ mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
+ mode_complete) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
+ mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>",
+ "name<arg<more>>",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg>",
+ "name<arg<more>>",
+ mode_compare) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
+ mode_compare) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
+ mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0);
+ SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0);
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0);
+ SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0);
+
+ SELF_CHECK (cooked_index_entry::compare ("func", "func<type>",
+ mode_sort) == 0);
+ SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1",
+ mode_sort) < 0);
+}
+
+} /* anonymous namespace */
+
+#endif /* GDB_SELF_TEST */
+
+/* See cooked-index-entry.h. */
+
+bool
+cooked_index_entry::matches (domain_search_flags kind) const
+{
+ /* Just reject type declarations. */
+ if ((flags & IS_TYPE_DECLARATION) != 0)
+ return false;
+
+ return tag_matches_domain (tag, kind, lang);
+}
+
+/* See cooked-index-entry.h. */
+
+const char *
+cooked_index_entry::full_name (struct obstack *storage,
+ cooked_index_full_name_flag name_flags,
+ const char *default_sep) const
+{
+ const char *local_name = ((name_flags & FOR_MAIN) != 0) ? name : canonical;
+
+ if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr)
+ return local_name;
+
+ const char *sep = default_sep;
+ switch (lang)
+ {
+ case language_cplus:
+ case language_rust:
+ case language_fortran:
+ sep = "::";
+ break;
+
+ case language_ada:
+ if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0)
+ {
+ sep = "__";
+ break;
+ }
+ [[fallthrough]];
+ case language_go:
+ case language_d:
+ sep = ".";
+ break;
+
+ default:
+ if (sep == nullptr)
+ return local_name;
+ break;
+ }
+
+ /* The FOR_ADA_LINKAGE_NAME flag should only affect Ada entries, so
+ disable it here if we don't need it. */
+ if (lang != language_ada)
+ name_flags &= ~FOR_ADA_LINKAGE_NAME;
+
+ get_parent ()->write_scope (storage, sep, name_flags);
+ obstack_grow0 (storage, local_name, strlen (local_name));
+ return (const char *) obstack_finish (storage);
+}
+
+/* See cooked-index-entry.h. */
+
+void
+cooked_index_entry::write_scope (struct obstack *storage,
+ const char *sep,
+ cooked_index_full_name_flag flags) const
+{
+ if (get_parent () != nullptr)
+ get_parent ()->write_scope (storage, sep, flags);
+ /* When computing the Ada linkage name, the entry might not have
+ been canonicalized yet, so use the 'name'. */
+ const char *local_name = ((flags & (FOR_MAIN | FOR_ADA_LINKAGE_NAME)) != 0
+ ? name
+ : canonical);
+ obstack_grow (storage, local_name, strlen (local_name));
+ obstack_grow (storage, sep, strlen (sep));
+}
+
+void _initialize_dwarf2_entry ();
+void _initialize_dwarf2_entry ()
+{
+#if GDB_SELF_TEST
+ selftests::register_test ("cooked_index_entry::compare", test_compare);
+#endif
+}
diff --git a/gdb/dwarf2/cooked-index-entry.h b/gdb/dwarf2/cooked-index-entry.h
new file mode 100644
index 0000000..bb47e32
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-entry.h
@@ -0,0 +1,258 @@
+/* Entry in the cooked index
+
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef GDB_DWARF2_COOKED_INDEX_ENTRY_H
+#define GDB_DWARF2_COOKED_INDEX_ENTRY_H
+
+#include "dwarf2/parent-map.h"
+#include "dwarf2/types.h"
+#include "symtab.h"
+#include "gdbsupport/gdb_obstack.h"
+#include "quick-symbol.h"
+
+/* Flags that describe an entry in the index. */
+enum cooked_index_flag_enum : unsigned char
+{
+ /* True if this entry is the program's "main". */
+ IS_MAIN = 1,
+ /* True if this entry represents a "static" object. */
+ IS_STATIC = 2,
+ /* True if this entry uses the linkage name. */
+ IS_LINKAGE = 4,
+ /* True if this entry is just for the declaration of a type, not the
+ definition. */
+ IS_TYPE_DECLARATION = 8,
+ /* True is parent_entry.deferred has a value rather than parent_entry
+ .resolved. */
+ IS_PARENT_DEFERRED = 16,
+ /* True if this entry was synthesized by gdb (as opposed to coming
+ directly from the DWARF). */
+ IS_SYNTHESIZED = 32,
+};
+DEF_ENUM_FLAGS_TYPE (enum cooked_index_flag_enum, cooked_index_flag);
+
+/* Flags used when requesting the full name of an entry. */
+enum cooked_index_full_name_enum : unsigned char
+{
+ /* Set when requesting the name of "main". See the method for the
+ full description. */
+ FOR_MAIN = 1,
+ /* Set when requesting the linkage name for an Ada entry. */
+ FOR_ADA_LINKAGE_NAME = 2,
+};
+DEF_ENUM_FLAGS_TYPE (enum cooked_index_full_name_enum, cooked_index_full_name_flag);
+
+/* Type representing either a resolved or deferred cooked_index_entry. */
+
+union cooked_index_entry_ref
+{
+ cooked_index_entry_ref (parent_map::addr_type deferred_)
+ {
+ deferred = deferred_;
+ }
+
+ cooked_index_entry_ref (const cooked_index_entry *resolved_)
+ {
+ resolved = resolved_;
+ }
+
+ const cooked_index_entry *resolved;
+ parent_map::addr_type deferred;
+};
+
+/* Return a string representation of FLAGS. */
+
+std::string to_string (cooked_index_flag flags);
+
+/* A cooked_index_entry represents a single item in the index. Note
+ that two entries can be created for the same DIE -- one using the
+ name, and another one using the linkage name, if any.
+
+ This is an "open" class and the members are all directly
+ accessible. It is read-only after the index has been fully read
+ and processed. */
+struct cooked_index_entry : public allocate_on_obstack<cooked_index_entry>
+{
+ cooked_index_entry (sect_offset die_offset_, enum dwarf_tag tag_,
+ cooked_index_flag flags_,
+ enum language lang_, const char *name_,
+ cooked_index_entry_ref parent_entry_,
+ dwarf2_per_cu *per_cu_)
+ : name (name_),
+ tag (tag_),
+ flags (flags_),
+ lang (lang_),
+ die_offset (die_offset_),
+ per_cu (per_cu_),
+ m_parent_entry (parent_entry_)
+ {
+ }
+
+ /* Return true if this entry matches SEARCH_FLAGS. */
+ bool matches (block_search_flags search_flags) const
+ {
+ /* Just reject type declarations. */
+ if ((flags & IS_TYPE_DECLARATION) != 0)
+ return false;
+
+ if ((search_flags & SEARCH_STATIC_BLOCK) != 0
+ && (flags & IS_STATIC) != 0)
+ return true;
+ if ((search_flags & SEARCH_GLOBAL_BLOCK) != 0
+ && (flags & IS_STATIC) == 0)
+ return true;
+ return false;
+ }
+
+ /* Return true if this entry matches KIND. */
+ bool matches (domain_search_flags kind) const;
+
+ /* Construct the fully-qualified name of this entry and return a
+ pointer to it. If allocation is needed, it will be done on
+ STORAGE.
+
+ FLAGS affects the result. If the FOR_MAIN flag is set, we are
+ computing the name of the "main" entry -- one marked
+ DW_AT_main_subprogram. This matters for avoiding name
+ canonicalization and also a related race (if "main" computation
+ is done during finalization).
+
+ If the FOR_ADA_LINKAGE_NAME flag is set, then Ada-language
+ symbols will have their "linkage-style" name computed. The
+ default is source-style.
+
+ If the language doesn't prescribe a separator, one can be
+ specified using DEFAULT_SEP. */
+ const char *full_name (struct obstack *storage,
+ cooked_index_full_name_flag name_flags = 0,
+ const char *default_sep = nullptr) const;
+
+ /* Comparison modes for the 'compare' function. See the function
+ for a description. */
+ enum comparison_mode
+ {
+ MATCH,
+ SORT,
+ COMPLETE,
+ };
+
+ /* Compare two strings, case-insensitively. Return -1 if STRA is
+ less than STRB, 0 if they are equal, and 1 if STRA is greater.
+
+ When comparing, '<' is considered to be less than all other
+ printable characters. This ensures that "t<x>" sorts before
+ "t1", which is necessary when looking up "t". This '<' handling
+ is to ensure that certain C++ lookups work correctly. It is
+ inexact, and applied regardless of the search language, but this
+ is ok because callers of this code do more precise filtering
+ according to their needs. This is also why using a
+ case-insensitive comparison works even for languages that are
+ case sensitive.
+
+ MODE controls how the comparison proceeds.
+
+ MODE==SORT is used when sorting and the only special '<' handling
+ that it does is to ensure that '<' sorts before all other
+ printable characters. This ensures that the resulting ordering
+ will be binary-searchable.
+
+ MODE==MATCH is used when searching for a symbol. In this case,
+ STRB must always be the search name, and STRA must be the name in
+ the index that is under consideration. In compare mode, early
+ termination of STRB may match STRA -- for example, "t<int>" and
+ "t" will be considered to be equal. (However, if A=="t" and
+ B=="t<int>", then this will not consider them as equal.)
+
+ MODE==COMPLETE is used when searching for a symbol for
+ completion. In this case, STRB must always be the search name,
+ and STRA must be the name in the index that is under
+ consideration. In completion mode, early termination of STRB
+ always results in a match. */
+ static int compare (const char *stra, const char *strb,
+ comparison_mode mode);
+
+ /* Compare two entries by canonical name. */
+ bool operator< (const cooked_index_entry &other) const
+ {
+ return compare (canonical, other.canonical, SORT) < 0;
+ }
+
+ /* Set parent entry to PARENT. */
+ void set_parent (const cooked_index_entry *parent)
+ {
+ gdb_assert ((flags & IS_PARENT_DEFERRED) == 0);
+ m_parent_entry.resolved = parent;
+ }
+
+ /* Resolve deferred parent entry to PARENT. */
+ void resolve_parent (const cooked_index_entry *parent)
+ {
+ gdb_assert ((flags & IS_PARENT_DEFERRED) != 0);
+ flags = flags & ~IS_PARENT_DEFERRED;
+ m_parent_entry.resolved = parent;
+ }
+
+ /* Return parent entry. */
+ const cooked_index_entry *get_parent () const
+ {
+ gdb_assert ((flags & IS_PARENT_DEFERRED) == 0);
+ return m_parent_entry.resolved;
+ }
+
+ /* Return deferred parent entry. */
+ parent_map::addr_type get_deferred_parent () const
+ {
+ gdb_assert ((flags & IS_PARENT_DEFERRED) != 0);
+ return m_parent_entry.deferred;
+ }
+
+ /* The name as it appears in DWARF. This always points into one of
+ the mapped DWARF sections. Note that this may be the name or the
+ linkage name -- two entries are created for DIEs which have both
+ attributes. */
+ const char *name;
+ /* The canonical name. This may be equal to NAME. */
+ const char *canonical = nullptr;
+ /* The DWARF tag. */
+ enum dwarf_tag tag;
+ /* Any flags attached to this entry. */
+ cooked_index_flag flags;
+ /* The language of this symbol. */
+ ENUM_BITFIELD (language) lang : LANGUAGE_BITS;
+ /* The offset of this DIE. */
+ sect_offset die_offset;
+ /* The CU from which this entry originates. */
+ dwarf2_per_cu *per_cu;
+
+private:
+
+ /* A helper method for full_name. Emits the full scope of this
+ object, followed by the separator, to STORAGE. If this entry has
+ a parent, its write_scope method is called first. See full_name
+ for a description of the FLAGS parameter. */
+ void write_scope (struct obstack *storage, const char *sep,
+ cooked_index_full_name_flag flags) const;
+
+ /* The parent entry. This is NULL for top-level entries.
+ Otherwise, it points to the parent entry, such as a namespace or
+ class. */
+ cooked_index_entry_ref m_parent_entry;
+};
+
+#endif /* GDB_DWARF2_COOKED_INDEX_ENTRY_H */
diff --git a/gdb/dwarf2/cooked-index-shard.c b/gdb/dwarf2/cooked-index-shard.c
new file mode 100644
index 0000000..683feb2
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-shard.c
@@ -0,0 +1,331 @@
+/* Shards for the cooked index
+
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "dwarf2/cooked-index-shard.h"
+#include "dwarf2/tag.h"
+#include "dwarf2/index-common.h"
+#include "cp-support.h"
+#include "c-lang.h"
+#include "ada-lang.h"
+
+/* Return true if a plain "main" could be the main program for this
+ language. Languages that are known to use some other mechanism are
+ excluded here. */
+
+static bool
+language_may_use_plain_main (enum language lang)
+{
+ /* No need to handle "unknown" here. */
+ return (lang == language_c
+ || lang == language_objc
+ || lang == language_cplus
+ || lang == language_m2
+ || lang == language_asm
+ || lang == language_opencl
+ || lang == language_minimal);
+}
+
+/* See cooked-index-shard.h. */
+
+cooked_index_entry *
+cooked_index_shard::create (sect_offset die_offset,
+ enum dwarf_tag tag,
+ cooked_index_flag flags,
+ enum language lang,
+ const char *name,
+ cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu)
+{
+ if (tag == DW_TAG_module || tag == DW_TAG_namespace)
+ flags &= ~IS_STATIC;
+ else if (lang == language_cplus
+ && (tag == DW_TAG_class_type
+ || tag == DW_TAG_interface_type
+ || tag == DW_TAG_structure_type
+ || tag == DW_TAG_union_type
+ || tag == DW_TAG_enumeration_type
+ || tag == DW_TAG_enumerator))
+ flags &= ~IS_STATIC;
+ else if (tag_is_type (tag))
+ flags |= IS_STATIC;
+
+ return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
+ lang, name, parent_entry,
+ per_cu);
+}
+
+/* See cooked-index-shard.h. */
+
+cooked_index_entry *
+cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag,
+ cooked_index_flag flags, enum language lang,
+ const char *name, cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu)
+{
+ cooked_index_entry *result = create (die_offset, tag, flags, lang, name,
+ parent_entry, per_cu);
+ m_entries.push_back (result);
+
+ /* An explicitly-tagged main program should always override the
+ implicit "main" discovery. */
+ if ((flags & IS_MAIN) != 0)
+ m_main = result;
+ else if ((flags & IS_PARENT_DEFERRED) == 0
+ && parent_entry.resolved == nullptr
+ && m_main == nullptr
+ && language_may_use_plain_main (lang)
+ && strcmp (name, "main") == 0)
+ m_main = result;
+
+ return result;
+}
+
+/* See cooked-index-shard.h. */
+
+void
+cooked_index_shard::handle_gnat_encoded_entry
+ (cooked_index_entry *entry,
+ htab_t gnat_entries,
+ std::vector<cooked_index_entry *> &new_entries)
+{
+ /* We decode Ada names in a particular way: operators and wide
+ characters are left as-is. This is done to make name matching a
+ bit simpler; and for wide characters, it means the choice of Ada
+ source charset does not affect the indexer directly. */
+ std::string canonical = ada_decode (entry->name, false, false, false);
+ if (canonical.empty ())
+ {
+ entry->canonical = entry->name;
+ return;
+ }
+ std::vector<std::string_view> names = split_name (canonical.c_str (),
+ split_style::DOT_STYLE);
+ std::string_view tail = names.back ();
+ names.pop_back ();
+
+ const cooked_index_entry *parent = nullptr;
+ for (const auto &name : names)
+ {
+ uint32_t hashval = dwarf5_djb_hash (name);
+ void **slot = htab_find_slot_with_hash (gnat_entries, &name,
+ hashval, INSERT);
+ /* CUs are processed in order, so we only need to check the most
+ recent entry. */
+ cooked_index_entry *last = (cooked_index_entry *) *slot;
+ if (last == nullptr || last->per_cu != entry->per_cu)
+ {
+ const char *new_name = m_names.insert (name);
+ last = create (entry->die_offset, DW_TAG_module,
+ IS_SYNTHESIZED, language_ada, new_name, parent,
+ entry->per_cu);
+ last->canonical = last->name;
+ new_entries.push_back (last);
+ *slot = last;
+ }
+
+ parent = last;
+ }
+
+ entry->set_parent (parent);
+ entry->canonical = m_names.insert (tail);
+}
+
+/* Hash a cooked index entry by name pointer value.
+
+ We can use pointer equality here because names come from .debug_str, which
+ will normally be unique-ified by the linker. Also, duplicates are relatively
+ harmless -- they just mean a bit of extra memory is used. */
+
+struct cooked_index_entry_name_ptr_hash
+{
+ using is_avalanching = void;
+
+ std::uint64_t operator () (const cooked_index_entry *entry) const noexcept
+ {
+ return ankerl::unordered_dense::hash<const char *> () (entry->name);
+ }
+};
+
+/* Compare cooked index entries by name pointer value. */
+
+struct cooked_index_entry_name_ptr_eq
+{
+ bool operator () (const cooked_index_entry *a,
+ const cooked_index_entry *b) const noexcept
+ {
+ return a->name == b->name;
+ }
+};
+
+/* See cooked-index-shard.h. */
+
+void
+cooked_index_shard::finalize (const parent_map_map *parent_maps)
+{
+ gdb::unordered_set<const cooked_index_entry *,
+ cooked_index_entry_name_ptr_hash,
+ cooked_index_entry_name_ptr_eq> seen_names;
+
+ auto hash_entry = [] (const void *e)
+ {
+ const cooked_index_entry *entry = (const cooked_index_entry *) e;
+ return dwarf5_djb_hash (entry->canonical);
+ };
+
+ auto eq_entry = [] (const void *a, const void *b) -> int
+ {
+ const cooked_index_entry *ae = (const cooked_index_entry *) a;
+ const std::string_view *sv = (const std::string_view *) b;
+ return (strlen (ae->canonical) == sv->length ()
+ && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
+ };
+
+ htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
+ nullptr, xcalloc, xfree));
+ std::vector<cooked_index_entry *> new_gnat_entries;
+
+ for (cooked_index_entry *entry : m_entries)
+ {
+ if ((entry->flags & IS_PARENT_DEFERRED) != 0)
+ {
+ const cooked_index_entry *new_parent
+ = parent_maps->find (entry->get_deferred_parent ());
+ entry->resolve_parent (new_parent);
+ }
+
+ /* Note that this code must be kept in sync with
+ language_requires_canonicalization. */
+ gdb_assert (entry->canonical == nullptr);
+ if ((entry->flags & IS_LINKAGE) != 0)
+ entry->canonical = entry->name;
+ else if (entry->lang == language_ada)
+ {
+ /* Newer versions of GNAT emit DW_TAG_module and use a
+ hierarchical structure. In this case, we don't need to
+ do any extra work. This can be detected by looking for a
+ GNAT-encoded name. */
+ if (strstr (entry->name, "__") == nullptr)
+ {
+ entry->canonical = entry->name;
+
+ /* If the entry does not have a parent, then there's
+ nothing extra to do here -- the entry itself is
+ sufficient.
+
+ However, if it does have a parent, we have to
+ synthesize an entry with the full name. This is
+ unfortunate, but it's necessary due to how some of
+ the Ada name-lookup code currently works. For
+ example, without this, ada_get_tsd_type will
+ fail.
+
+ Eventually it would be good to change the Ada lookup
+ code, and then remove these entries (and supporting
+ code in cooked_index_entry::full_name). */
+ if (entry->get_parent () != nullptr)
+ {
+ const char *fullname
+ = entry->full_name (&m_storage, FOR_ADA_LINKAGE_NAME);
+ cooked_index_entry *linkage = create (entry->die_offset,
+ entry->tag,
+ (entry->flags
+ | IS_LINKAGE
+ | IS_SYNTHESIZED),
+ language_ada,
+ fullname,
+ nullptr,
+ entry->per_cu);
+ linkage->canonical = fullname;
+ new_gnat_entries.push_back (linkage);
+ }
+ }
+ else
+ handle_gnat_encoded_entry (entry, gnat_entries.get (),
+ new_gnat_entries);
+ }
+ else if (entry->lang == language_cplus || entry->lang == language_c)
+ {
+ auto [it, inserted] = seen_names.insert (entry);
+
+ if (inserted)
+ {
+ /* No entry with that name was present, compute the canonical
+ name. */
+ gdb::unique_xmalloc_ptr<char> canon_name
+ = (entry->lang == language_cplus
+ ? cp_canonicalize_string (entry->name)
+ : c_canonicalize_name (entry->name));
+ if (canon_name == nullptr)
+ entry->canonical = entry->name;
+ else
+ entry->canonical = m_names.insert (std::move (canon_name));
+ }
+ else
+ {
+ /* An entry with that name was present, re-use its canonical
+ name. */
+ entry->canonical = (*it)->canonical;
+ }
+ }
+ else
+ entry->canonical = entry->name;
+ }
+
+ /* Make sure any new Ada entries end up in the results. This isn't
+ done when creating these new entries to avoid invalidating the
+ m_entries iterator used in the foreach above. */
+ m_entries.insert (m_entries.end (), new_gnat_entries.begin (),
+ new_gnat_entries.end ());
+
+ m_entries.shrink_to_fit ();
+ std::sort (m_entries.begin (), m_entries.end (),
+ [] (const cooked_index_entry *a, const cooked_index_entry *b)
+ {
+ return *a < *b;
+ });
+}
+
+/* See cooked-index-shard.h. */
+
+cooked_index_shard::range
+cooked_index_shard::find (const std::string &name, bool completing) const
+{
+ struct comparator
+ {
+ cooked_index_entry::comparison_mode mode;
+
+ bool operator() (const cooked_index_entry *entry,
+ const char *name) const noexcept
+ {
+ return cooked_index_entry::compare (entry->canonical, name, mode) < 0;
+ }
+
+ bool operator() (const char *name,
+ const cooked_index_entry *entry) const noexcept
+ {
+ return cooked_index_entry::compare (entry->canonical, name, mode) > 0;
+ }
+ };
+
+ return std::make_from_tuple<range>
+ (std::equal_range (m_entries.cbegin (), m_entries.cend (), name.c_str (),
+ comparator { (completing
+ ? cooked_index_entry::COMPLETE
+ : cooked_index_entry::MATCH) }));
+}
diff --git a/gdb/dwarf2/cooked-index-shard.h b/gdb/dwarf2/cooked-index-shard.h
new file mode 100644
index 0000000..eb80926
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-shard.h
@@ -0,0 +1,134 @@
+/* Shards for the cooked index
+
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef GDB_DWARF2_COOKED_INDEX_SHARD_H
+#define GDB_DWARF2_COOKED_INDEX_SHARD_H
+
+#include "dwarf2/cooked-index-entry.h"
+#include "dwarf2/types.h"
+#include "gdbsupport/gdb_obstack.h"
+#include "addrmap.h"
+#include "gdbsupport/iterator-range.h"
+#include "gdbsupport/string-set.h"
+
+/* An index of interesting DIEs. This is "cooked", in contrast to a
+ mapped .debug_names or .gdb_index, which are "raw". An entry in
+ the index is of type cooked_index_entry.
+
+ Operations on the index are described below. They are chosen to
+ make it relatively simple to implement the symtab "quick"
+ methods. */
+class cooked_index_shard
+{
+public:
+ cooked_index_shard () = default;
+ DISABLE_COPY_AND_ASSIGN (cooked_index_shard);
+
+ /* Create a new cooked_index_entry and register it with this object.
+ Entries are owned by this object. The new item is returned. */
+ cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+ cooked_index_flag flags, enum language lang,
+ const char *name,
+ cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu);
+
+ /* Install a new fixed addrmap from the given mutable addrmap. */
+ void install_addrmap (addrmap_mutable *map)
+ {
+ gdb_assert (m_addrmap == nullptr);
+ m_addrmap = new (&m_storage) addrmap_fixed (&m_storage, map);
+ }
+
+ friend class cooked_index;
+
+ /* A simple range over part of m_entries. */
+ typedef iterator_range<std::vector<cooked_index_entry *>::const_iterator>
+ range;
+
+ /* Return a range of all the entries. */
+ range all_entries () const
+ {
+ return { m_entries.cbegin (), m_entries.cend () };
+ }
+
+ /* Look up an entry by name. Returns a range of all matching
+ results. If COMPLETING is true, then a larger range, suitable
+ for completion, will be returned. */
+ range find (const std::string &name, bool completing) const;
+
+private:
+
+ /* Return the entry that is believed to represent the program's
+ "main". This will return NULL if no such entry is available. */
+ const cooked_index_entry *get_main () const
+ {
+ return m_main;
+ }
+
+ /* Look up ADDR in the address map, and return either the
+ corresponding CU, or nullptr if the address could not be
+ found. */
+ dwarf2_per_cu *lookup (unrelocated_addr addr)
+ {
+ if (m_addrmap == nullptr)
+ return nullptr;
+
+ return (static_cast<dwarf2_per_cu *> (m_addrmap->find ((CORE_ADDR) addr)));
+ }
+
+ /* Create a new cooked_index_entry and register it with this object.
+ Entries are owned by this object. The new item is returned. */
+ cooked_index_entry *create (sect_offset die_offset,
+ enum dwarf_tag tag,
+ cooked_index_flag flags,
+ enum language lang,
+ const char *name,
+ cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu);
+
+ /* When GNAT emits mangled ("encoded") names in the DWARF, and does
+ not emit the module structure, we still need this structuring to
+ do lookups. This function recreates that information for an
+ existing entry, modifying ENTRY as appropriate. Any new entries
+ are added to NEW_ENTRIES. */
+ void handle_gnat_encoded_entry
+ (cooked_index_entry *entry, htab_t gnat_entries,
+ std::vector<cooked_index_entry *> &new_entries);
+
+ /* Finalize the index. This should be called a single time, when
+ the index has been fully populated. It enters all the entries
+ into the internal table and fixes up all missing parent links.
+ This may be invoked in a worker thread. */
+ void finalize (const parent_map_map *parent_maps);
+
+ /* Storage for the entries. */
+ auto_obstack m_storage;
+ /* List of all entries. */
+ std::vector<cooked_index_entry *> m_entries;
+ /* If we found an entry with 'is_main' set, store it here. */
+ cooked_index_entry *m_main = nullptr;
+ /* The addrmap. This maps address ranges to dwarf2_per_cu objects. */
+ addrmap_fixed *m_addrmap = nullptr;
+ /* Storage for canonical names. */
+ gdb::string_set m_names;
+};
+
+using cooked_index_shard_up = std::unique_ptr<cooked_index_shard>;
+
+#endif /* GDB_DWARF2_COOKED_INDEX_SHARD_H */
diff --git a/gdb/dwarf2/cooked-index-storage.c b/gdb/dwarf2/cooked-index-storage.c
deleted file mode 100644
index 9c05cf5..0000000
--- a/gdb/dwarf2/cooked-index-storage.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* DWARF index storage
-
- Copyright (C) 2022-2025 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- 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/>. */
-
-#include "dwarf2/cooked-index-storage.h"
-
-/* See cooked-index-storage.h. */
-
-cooked_index_storage::cooked_index_storage ()
- : m_shard (new cooked_index_shard)
-{
-}
-
-/* See cooked-index-storage.h. */
-
-cutu_reader *
-cooked_index_storage::get_reader (dwarf2_per_cu *per_cu)
-{
- auto it = m_reader_hash.find (*per_cu);
- return it != m_reader_hash.end () ? it->get () : nullptr;
-}
-
-/* See cooked-index-storage.h. */
-
-cutu_reader *
-cooked_index_storage::preserve (cutu_reader_up reader)
-{
- m_abbrev_table_cache.add (reader->release_abbrev_table ());
-
- auto [it, inserted] = m_reader_hash.insert (std::move (reader));
- gdb_assert (inserted);
-
- return it->get();
-}
-
-/* See cooked-index-storage.h. */
-
-std::uint64_t
-cooked_index_storage::cutu_reader_hash::operator()
- (const cutu_reader_up &reader) const noexcept
-{
- return (*this) (*reader->cu ()->per_cu);
-}
-
-/* See cooked-index-storage.h. */
-
-std::uint64_t
-cooked_index_storage::cutu_reader_hash::operator() (const dwarf2_per_cu &per_cu)
- const noexcept
-{
- return per_cu.index;
-}
-
-/* See cooked-index-storage.h. */
-
-bool
-cooked_index_storage::cutu_reader_eq::operator() (const cutu_reader_up &a,
- const cutu_reader_up &b) const noexcept
-{
- return (*this) (*a->cu ()->per_cu, b);
-}
-
-/* See cooked-index-storage.h. */
-
-bool cooked_index_storage::cutu_reader_eq::operator()
- (const dwarf2_per_cu &per_cu, const cutu_reader_up &reader) const noexcept
-{
- return per_cu.index == reader->cu ()->per_cu->index;
-}
diff --git a/gdb/dwarf2/cooked-index-storage.h b/gdb/dwarf2/cooked-index-storage.h
deleted file mode 100644
index 449fbe1..0000000
--- a/gdb/dwarf2/cooked-index-storage.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* DWARF index storage
-
- Copyright (C) 2022-2025 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- 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/>. */
-
-#ifndef GDB_DWARF2_COOKED_INDEX_STORAGE_H
-#define GDB_DWARF2_COOKED_INDEX_STORAGE_H
-
-#include "dwarf2/abbrev-table-cache.h"
-#include "dwarf2/cooked-index.h"
-#include "dwarf2/types.h"
-
-struct cutu_reader;
-struct dwarf2_per_cu;
-
-using cutu_reader_up = std::unique_ptr<cutu_reader>;
-
-/* An instance of this is created when scanning DWARF to create a
- cooked index. */
-
-class cooked_index_storage
-{
-public:
-
- cooked_index_storage ();
- DISABLE_COPY_AND_ASSIGN (cooked_index_storage);
-
- /* Return the current abbrev table_cache. */
- const abbrev_table_cache &get_abbrev_table_cache () const
- { return m_abbrev_table_cache; }
-
- /* Return the DIE reader corresponding to PER_CU. If no such reader
- has been registered, return NULL. */
- cutu_reader *get_reader (dwarf2_per_cu *per_cu);
-
- /* Preserve READER by storing it in the local hash table. */
- cutu_reader *preserve (cutu_reader_up reader);
-
- /* Add an entry to the index. The arguments describe the entry; see
- cooked-index.h. The new entry is returned. */
- cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
- cooked_index_flag flags,
- const char *name,
- cooked_index_entry_ref parent_entry,
- dwarf2_per_cu *per_cu)
- {
- return m_shard->add (die_offset, tag, flags, per_cu->lang (),
- name, parent_entry, per_cu);
- }
-
- /* Install the current addrmap into the shard being constructed,
- then transfer ownership of the index to the caller. */
- cooked_index_shard_up release ()
- {
- m_shard->install_addrmap (&m_addrmap);
- return std::move (m_shard);
- }
-
- /* Return the mutable addrmap that is currently being created. */
- addrmap_mutable *get_addrmap ()
- {
- return &m_addrmap;
- }
-
- /* Return the parent_map that is currently being created. */
- parent_map *get_parent_map ()
- {
- return &m_parent_map;
- }
-
- /* Return the parent_map that is currently being created. Ownership
- is passed to the caller. */
- parent_map release_parent_map ()
- {
- return std::move (m_parent_map);
- }
-
-private:
- /* The abbrev table cache used by this indexer. */
- abbrev_table_cache m_abbrev_table_cache;
-
- /* Hash function for a cutu_reader. */
- struct cutu_reader_hash
- {
- using is_transparent = void;
-
- std::uint64_t operator() (const cutu_reader_up &reader) const noexcept;
- std::uint64_t operator() (const dwarf2_per_cu &per_cu) const noexcept;
- };
-
- /* Equality function for cutu_reader. */
- struct cutu_reader_eq
- {
- using is_transparent = void;
-
- bool operator() (const cutu_reader_up &a,
- const cutu_reader_up &b) const noexcept;
-
- bool operator() (const dwarf2_per_cu &per_cu,
- const cutu_reader_up &reader) const noexcept;
- };
-
- /* A hash table of cutu_reader objects. */
- gdb::unordered_set<cutu_reader_up, cutu_reader_hash, cutu_reader_eq>
- m_reader_hash;
-
- /* The index shard that is being constructed. */
- cooked_index_shard_up m_shard;
-
- /* Parent map for each CU that is read. */
- parent_map m_parent_map;
-
- /* A writeable addrmap being constructed by this scanner. */
- addrmap_mutable m_addrmap;
-};
-
-#endif /* GDB_DWARF2_COOKED_INDEX_STORAGE_H */
diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c
new file mode 100644
index 0000000..da51a8c
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-worker.c
@@ -0,0 +1,255 @@
+/* DWARF index storage
+
+ Copyright (C) 2022-2025 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "dwarf2/cooked-index-worker.h"
+#include "dwarf2/cooked-index.h"
+#include "gdbsupport/thread-pool.h"
+#include "run-on-main-thread.h"
+#include "event-top.h"
+#include "exceptions.h"
+
+/* See cooked-index-worker.h. */
+
+cooked_index_worker_result::cooked_index_worker_result ()
+ : m_shard (new cooked_index_shard)
+{
+}
+
+/* See cooked-index-worker.h. */
+
+cutu_reader *
+cooked_index_worker_result::get_reader (dwarf2_per_cu *per_cu)
+{
+ auto it = m_reader_hash.find (*per_cu);
+ return it != m_reader_hash.end () ? it->get () : nullptr;
+}
+
+/* See cooked-index-worker.h. */
+
+cutu_reader *
+cooked_index_worker_result::preserve (cutu_reader_up reader)
+{
+ m_abbrev_table_cache.add (reader->release_abbrev_table ());
+
+ auto [it, inserted] = m_reader_hash.insert (std::move (reader));
+ gdb_assert (inserted);
+
+ return it->get();
+}
+
+/* See cooked-index-worker.h. */
+
+std::uint64_t
+cooked_index_worker_result::cutu_reader_hash::operator()
+ (const cutu_reader_up &reader) const noexcept
+{
+ return (*this) (*reader->cu ()->per_cu);
+}
+
+/* See cooked-index-worker.h. */
+
+std::uint64_t
+cooked_index_worker_result::cutu_reader_hash::operator() (const dwarf2_per_cu &per_cu)
+ const noexcept
+{
+ return per_cu.index;
+}
+
+/* See cooked-index-worker.h. */
+
+bool
+cooked_index_worker_result::cutu_reader_eq::operator() (const cutu_reader_up &a,
+ const cutu_reader_up &b) const noexcept
+{
+ return (*this) (*a->cu ()->per_cu, b);
+}
+
+/* See cooked-index-worker.h. */
+
+bool cooked_index_worker_result::cutu_reader_eq::operator()
+ (const dwarf2_per_cu &per_cu, const cutu_reader_up &reader) const noexcept
+{
+ return per_cu.index == reader->cu ()->per_cu->index;
+}
+
+/* See cooked-index-worker.h. */
+
+void
+cooked_index_worker_result::emit_complaints_and_exceptions
+ (gdb::unordered_set<gdb_exception> &seen_exceptions)
+{
+ gdb_assert (is_main_thread ());
+
+ re_emit_complaints (m_complaints);
+
+ /* Only show a given exception a single time. */
+ for (auto &one_exc : m_exceptions)
+ if (seen_exceptions.insert (one_exc).second)
+ exception_print (gdb_stderr, one_exc);
+}
+
+/* See cooked-index-worker.h. */
+
+void
+cooked_index_worker::start ()
+{
+ gdb::thread_pool::g_thread_pool->post_task ([this] ()
+ {
+ try
+ {
+ do_reading ();
+ }
+ catch (const gdb_exception &exc)
+ {
+ m_failed = exc;
+ set (cooked_state::CACHE_DONE);
+ }
+
+ bfd_thread_cleanup ();
+ });
+}
+
+/* See cooked-index-worker.h. */
+
+bool
+cooked_index_worker::wait (cooked_state desired_state, bool allow_quit)
+{
+ bool done;
+#if CXX_STD_THREAD
+ {
+ std::unique_lock<std::mutex> lock (m_mutex);
+
+ /* This may be called from a non-main thread -- this functionality
+ is needed for the index cache -- but in this case we require
+ that the desired state already have been attained. */
+ gdb_assert (is_main_thread () || desired_state <= m_state);
+
+ while (desired_state > m_state)
+ {
+ if (allow_quit)
+ {
+ std::chrono::milliseconds duration { 15 };
+ if (m_cond.wait_for (lock, duration) == std::cv_status::timeout)
+ QUIT;
+ }
+ else
+ m_cond.wait (lock);
+ }
+ done = m_state == cooked_state::CACHE_DONE;
+ }
+#else
+ /* Without threads, all the work is done immediately on the main
+ thread, and there is never anything to wait for. */
+ done = desired_state == cooked_state::CACHE_DONE;
+#endif /* CXX_STD_THREAD */
+
+ /* Only the main thread is allowed to report complaints and the
+ like. */
+ if (!is_main_thread ())
+ return false;
+
+ if (m_reported)
+ return done;
+ m_reported = true;
+
+ /* Emit warnings first, maybe they were emitted before an exception
+ (if any) was thrown. */
+ m_warnings.emit ();
+
+ if (m_failed.has_value ())
+ {
+ /* do_reading failed -- report it. */
+ exception_print (gdb_stderr, *m_failed);
+ m_failed.reset ();
+ return done;
+ }
+
+ /* Only show a given exception a single time. */
+ gdb::unordered_set<gdb_exception> seen_exceptions;
+ for (auto &one_result : m_results)
+ one_result.emit_complaints_and_exceptions (seen_exceptions);
+
+ print_stats ();
+
+ struct objfile *objfile = m_per_objfile->objfile;
+ dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
+ cooked_index *table
+ = (gdb::checked_static_cast<cooked_index *>
+ (per_bfd->index_table.get ()));
+
+ auto_obstack temp_storage;
+ enum language lang = language_unknown;
+ const char *main_name = table->get_main_name (&temp_storage, &lang);
+ if (main_name != nullptr)
+ set_objfile_main_name (objfile, main_name, lang);
+
+ /* dwarf_read_debug_printf ("Done building psymtabs of %s", */
+ /* objfile_name (objfile)); */
+
+ return done;
+}
+
+/* See cooked-index-worker.h. */
+
+void
+cooked_index_worker::set (cooked_state desired_state)
+{
+ gdb_assert (desired_state != cooked_state::INITIAL);
+
+#if CXX_STD_THREAD
+ std::lock_guard<std::mutex> guard (m_mutex);
+ gdb_assert (desired_state > m_state);
+ m_state = desired_state;
+ m_cond.notify_one ();
+#else
+ /* Without threads, all the work is done immediately on the main
+ thread, and there is never anything to do. */
+#endif /* CXX_STD_THREAD */
+}
+
+/* See cooked-index-worker.h. */
+
+void
+cooked_index_worker::write_to_cache (const cooked_index *idx)
+{
+ if (idx != nullptr)
+ {
+ /* Writing to the index cache may cause a warning to be emitted.
+ See PR symtab/30837. This arranges to capture all such
+ warnings. This is safe because we know the deferred_warnings
+ object isn't in use by any other thread at this point. */
+ scoped_restore_warning_hook defer (&m_warnings);
+ m_cache_store.store ();
+ }
+}
+
+/* See cooked-index-worker.h. */
+
+void
+cooked_index_worker::done_reading ()
+{
+ for (auto &one_result : m_results)
+ m_all_parents_map.add_map (*one_result.get_parent_map ());
+
+ dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
+ cooked_index *table
+ = (gdb::checked_static_cast<cooked_index *>
+ (per_bfd->index_table.get ()));
+ table->set_contents ();
+}
diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h
new file mode 100644
index 0000000..df5c31d
--- /dev/null
+++ b/gdb/dwarf2/cooked-index-worker.h
@@ -0,0 +1,305 @@
+/* DWARF index storage
+
+ Copyright (C) 2022-2025 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef GDB_DWARF2_COOKED_INDEX_WORKER_H
+#define GDB_DWARF2_COOKED_INDEX_WORKER_H
+
+#include "dwarf2/abbrev-table-cache.h"
+#include "dwarf2/cooked-index-entry.h"
+#include "dwarf2/cooked-index-shard.h"
+#include "dwarf2/types.h"
+#include "dwarf2/read.h"
+
+#if CXX_STD_THREAD
+#include <mutex>
+#include <condition_variable>
+#endif /* CXX_STD_THREAD */
+
+using cutu_reader_up = std::unique_ptr<cutu_reader>;
+
+/* An instance of this is created when scanning DWARF to create a
+ cooked index. This class is the result of a single task to store
+ results while working -- that is, it is an implementation detail of
+ the threads managed by cooked_index_worker. Once scanning is done,
+ selected parts of the state here are stored into the shard, and
+ then these temporary objects are destroyed. */
+
+class cooked_index_worker_result
+{
+public:
+
+ cooked_index_worker_result ();
+ DISABLE_COPY_AND_ASSIGN (cooked_index_worker_result);
+
+ cooked_index_worker_result (cooked_index_worker_result &&) = default;
+ cooked_index_worker_result &operator= (cooked_index_worker_result &&)
+ = default;
+
+ /* Return the current abbrev table_cache. */
+ const abbrev_table_cache &get_abbrev_table_cache () const
+ { return m_abbrev_table_cache; }
+
+ /* Return the DIE reader corresponding to PER_CU. If no such reader
+ has been registered, return NULL. */
+ cutu_reader *get_reader (dwarf2_per_cu *per_cu);
+
+ /* Preserve READER by storing it in the local hash table. */
+ cutu_reader *preserve (cutu_reader_up reader);
+
+ /* Add an entry to the index. The arguments describe the entry; see
+ cooked-index.h. The new entry is returned. */
+ cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+ cooked_index_flag flags,
+ const char *name,
+ cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu)
+ {
+ return m_shard->add (die_offset, tag, flags, per_cu->lang (),
+ name, parent_entry, per_cu);
+ }
+
+ /* Overload that allows the language to be specified. */
+ cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+ cooked_index_flag flags, enum language lang,
+ const char *name,
+ cooked_index_entry_ref parent_entry,
+ dwarf2_per_cu *per_cu)
+ {
+ return m_shard->add (die_offset, tag, flags, lang,
+ name, parent_entry, per_cu);
+ }
+
+ /* Install the current addrmap into the shard being constructed,
+ then transfer ownership of the index to the caller. */
+ cooked_index_shard_up release_shard ()
+ {
+ m_shard->install_addrmap (&m_addrmap);
+ /* This isn't needed any more. */
+ m_addrmap.clear ();
+ return std::move (m_shard);
+ }
+
+ /* Return the mutable addrmap that is currently being created. */
+ addrmap_mutable *get_addrmap ()
+ {
+ return &m_addrmap;
+ }
+
+ /* Return the parent_map that is currently being created. */
+ parent_map *get_parent_map ()
+ {
+ return &m_parent_map;
+ }
+
+ /* Add an exception to the list of exceptions caught while reading.
+ These are passed forward and printed by the main thread. */
+ void note_error (gdb_exception &&except)
+ {
+ m_exceptions.push_back (std::move (except));
+ }
+
+ /* Called when the thread using this object is done with its work.
+ This stores any complaints for later emission, and it clears some
+ data that won't be needed again. */
+ void done_reading (complaint_collection &&complaints)
+ {
+ /* Hang on to the complaints. */
+ m_complaints = std::move (complaints);
+ /* Discard things that are no longer needed. */
+ m_reader_hash.clear ();
+ }
+
+ /* Called to emit any stored complaints or exceptions. This can
+ only be called on the main thread. */
+ void emit_complaints_and_exceptions
+ (gdb::unordered_set<gdb_exception> &seen_exceptions);
+
+private:
+ /* The abbrev table cache used by this indexer. */
+ abbrev_table_cache m_abbrev_table_cache;
+
+ /* Hash function for a cutu_reader. */
+ struct cutu_reader_hash
+ {
+ using is_transparent = void;
+
+ std::uint64_t operator() (const cutu_reader_up &reader) const noexcept;
+ std::uint64_t operator() (const dwarf2_per_cu &per_cu) const noexcept;
+ };
+
+ /* Equality function for cutu_reader. */
+ struct cutu_reader_eq
+ {
+ using is_transparent = void;
+
+ bool operator() (const cutu_reader_up &a,
+ const cutu_reader_up &b) const noexcept;
+
+ bool operator() (const dwarf2_per_cu &per_cu,
+ const cutu_reader_up &reader) const noexcept;
+ };
+
+ /* A hash table of cutu_reader objects. */
+ gdb::unordered_set<cutu_reader_up, cutu_reader_hash, cutu_reader_eq>
+ m_reader_hash;
+
+ /* The index shard that is being constructed. */
+ cooked_index_shard_up m_shard;
+
+ /* Parent map for each CU that is read. */
+ parent_map m_parent_map;
+
+ /* A writeable addrmap being constructed by this scanner. */
+ addrmap_mutable m_addrmap;
+
+ /* The issued complaints. Only set after done_reading is
+ called. */
+ complaint_collection m_complaints;
+
+ /* Exceptions that we're storing to emit later. */
+ std::vector<gdb_exception> m_exceptions;
+};
+
+/* The possible states of the index. See the explanatory comment
+ before cooked_index for more details. */
+enum class cooked_state
+{
+ /* The default state. This is not a valid argument to 'wait'. */
+ INITIAL,
+ /* The initial scan has completed. The name of "main" is now
+ available (if known). The addrmaps are usable now.
+ Finalization has started but is not complete. */
+ MAIN_AVAILABLE,
+ /* Finalization has completed. This means the index is fully
+ available for queries. */
+ FINALIZED,
+ /* Writing to the index cache has finished. */
+ CACHE_DONE,
+};
+
+/* An object of this type controls the scanning of the DWARF. It
+ schedules the worker tasks and tracks the current state. Once
+ scanning is done, this object is discarded.
+
+ This is an abstract base class that defines the basic behavior of
+ scanners. Separate concrete implementations exist for scanning
+ .debug_names and .debug_info. */
+
+class cooked_index_worker
+{
+public:
+
+ explicit cooked_index_worker (dwarf2_per_objfile *per_objfile)
+ : m_per_objfile (per_objfile),
+ m_cache_store (global_index_cache, per_objfile->per_bfd)
+ { }
+ virtual ~cooked_index_worker ()
+ { }
+ DISABLE_COPY_AND_ASSIGN (cooked_index_worker);
+
+ /* Start reading. */
+ void start ();
+
+ /* Wait for a particular state to be achieved. If ALLOW_QUIT is
+ true, then the loop will check the QUIT flag. Normally this
+ method may only be called from the main thread; however, it can
+ be called from a worker thread provided that the desired state
+ has already been attained. (This oddity is used by the index
+ cache writer.) */
+ bool wait (cooked_state desired_state, bool allow_quit);
+
+ /* Release all shards from the results. */
+ std::vector<cooked_index_shard_up> release_shards ()
+ {
+ std::vector<cooked_index_shard_up> result;
+ for (auto &one_result : m_results)
+ result.push_back (one_result.release_shard ());
+ result.shrink_to_fit ();
+ return result;
+ }
+
+ /* Return the object holding all the parent maps. */
+ const parent_map_map *get_parent_map_map () const
+ {
+ return &m_all_parents_map;
+ }
+
+protected:
+
+ /* Let cooked_index call the 'set' and 'write_to_cache' methods. */
+ friend class cooked_index;
+
+ /* Set the current state. */
+ void set (cooked_state desired_state);
+
+ /* Write to the index cache. */
+ void write_to_cache (const cooked_index *idx);
+
+ /* Helper function that does the work of reading. This must be able
+ to be run in a worker thread without problems. */
+ virtual void do_reading () = 0;
+
+ /* Helper function that should be called when done reading. This
+ assumes that m_results is filled in, and will initialize
+ m_all_parents_map and end by calling
+ cooked_index::set_contents. */
+ virtual void done_reading ();
+
+ /* A callback that can print stats, if needed. This is called when
+ transitioning to the 'MAIN_AVAILABLE' state. */
+ virtual void print_stats ()
+ { }
+
+ /* The per-objfile object. */
+ dwarf2_per_objfile *m_per_objfile;
+ /* Result of each worker task. */
+ std::vector<cooked_index_worker_result> m_results;
+ /* Any warnings emitted. For the time being at least, this only
+ needed in do_reading, not in every worker. Note that
+ deferred_warnings uses gdb_stderr in its constructor, and this
+ should only be done from the main thread. This is enforced in
+ the cooked_index_worker constructor. */
+ deferred_warnings m_warnings;
+
+ /* A map of all parent maps. Used during finalization to fix up
+ parent relationships. */
+ parent_map_map m_all_parents_map;
+
+#if CXX_STD_THREAD
+ /* Current state of this object. */
+ cooked_state m_state = cooked_state::INITIAL;
+ /* Mutex and condition variable used to synchronize. */
+ std::mutex m_mutex;
+ std::condition_variable m_cond;
+#endif /* CXX_STD_THREAD */
+ /* This flag indicates whether any complaints or exceptions that
+ arose during scanning have been reported by 'wait'. This may
+ only be modified on the main thread. */
+ bool m_reported = false;
+ /* If set, an exception occurred during reading; in this case the
+ scanning is stopped and this exception will later be reported by
+ the 'wait' method. */
+ std::optional<gdb_exception> m_failed;
+ /* An object used to write to the index cache. */
+ index_cache_store_context m_cache_store;
+};
+
+using cooked_index_worker_up = std::unique_ptr<cooked_index_worker>;
+
+#endif /* GDB_DWARF2_COOKED_INDEX_WORKER_H */
diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
index 724615f..0f20b07 100644
--- a/gdb/dwarf2/cooked-index.c
+++ b/gdb/dwarf2/cooked-index.c
@@ -18,25 +18,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "dwarf2/cooked-index.h"
-#include "dwarf2/index-common.h"
#include "dwarf2/read.h"
#include "dwarf2/stringify.h"
-#include "dwarf2/index-cache.h"
-#include "cp-support.h"
-#include "c-lang.h"
-#include "ada-lang.h"
-#include "dwarf2/tag.h"
#include "event-top.h"
-#include "exceptions.h"
-#include "split-name.h"
#include "observable.h"
#include "run-on-main-thread.h"
-#include <algorithm>
-#include "gdbsupport/gdb-safe-ctype.h"
-#include "gdbsupport/selftest.h"
#include "gdbsupport/task-group.h"
-#include "gdbsupport/thread-pool.h"
-#include <chrono>
#include "cli/cli-cmds.h"
/* We don't want gdb to exit while it is in the process of writing to
@@ -44,25 +31,12 @@
here, and then these are all waited for before exit proceeds. */
static gdb::unordered_set<cooked_index *> active_vectors;
-/* See cooked-index.h. */
-
-std::string
-to_string (cooked_index_flag flags)
-{
- static constexpr cooked_index_flag::string_mapping mapping[] = {
- MAP_ENUM_FLAG (IS_MAIN),
- MAP_ENUM_FLAG (IS_STATIC),
- MAP_ENUM_FLAG (IS_LINKAGE),
- MAP_ENUM_FLAG (IS_TYPE_DECLARATION),
- MAP_ENUM_FLAG (IS_PARENT_DEFERRED),
- };
-
- return flags.to_string (mapping);
-}
-
-/* See cooked-index.h. */
+/* Return true if LANG requires canonicalization. This is used
+ primarily to work around an issue computing the name of "main".
+ This function must be kept in sync with
+ cooked_index_shard::finalize. */
-bool
+static bool
language_requires_canonicalization (enum language lang)
{
return (lang == language_ada
@@ -70,648 +44,6 @@ language_requires_canonicalization (enum language lang)
|| lang == language_cplus);
}
-/* Return true if a plain "main" could be the main program for this
- language. Languages that are known to use some other mechanism are
- excluded here. */
-
-static bool
-language_may_use_plain_main (enum language lang)
-{
- /* No need to handle "unknown" here. */
- return (lang == language_c
- || lang == language_objc
- || lang == language_cplus
- || lang == language_m2
- || lang == language_asm
- || lang == language_opencl
- || lang == language_minimal);
-}
-
-/* See cooked-index.h. */
-
-int
-cooked_index_entry::compare (const char *stra, const char *strb,
- comparison_mode mode)
-{
-#if defined (__GNUC__) && !defined (__clang__) && __GNUC__ <= 7
- /* Work around error with gcc 7.5.0. */
- auto munge = [] (char c) -> unsigned char
-#else
- auto munge = [] (char c) constexpr -> unsigned char
-#endif
- {
- /* Treat '<' as if it ended the string. This lets something
- like "func<t>" match "func<t<int>>". See the "Breakpoints in
- template functions" section in the manual. */
- if (c == '<')
- return '\0';
- return TOLOWER ((unsigned char) c);
- };
-
- unsigned char a = munge (*stra);
- unsigned char b = munge (*strb);
-
- while (a != '\0' && b != '\0' && a == b)
- {
- a = munge (*++stra);
- b = munge (*++strb);
- }
-
- if (a == b)
- return 0;
-
- /* When completing, if STRB ends earlier than STRA, consider them as
- equal. */
- if (mode == COMPLETE || (mode == MATCH && a == munge ('<')))
- {
- if (b == '\0')
- return 0;
- }
-
- return a < b ? -1 : 1;
-}
-
-#if GDB_SELF_TEST
-
-namespace {
-
-void
-test_compare ()
-{
- /* Convenience aliases. */
- const auto mode_compare = cooked_index_entry::MATCH;
- const auto mode_sort = cooked_index_entry::SORT;
- const auto mode_complete = cooked_index_entry::COMPLETE;
-
- SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
- mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
- mode_compare) < 0);
- SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
- mode_compare) > 0);
- SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
- mode_complete) < 0);
- SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
- mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
- mode_complete) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
- mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
- mode_complete) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
- mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>",
- "name<arg<more>>",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg>",
- "name<arg<more>>",
- mode_compare) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
- mode_compare) == 0);
- SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
- mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0);
- SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0);
- SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0);
- SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0);
-
- SELF_CHECK (cooked_index_entry::compare ("func", "func<type>",
- mode_sort) == 0);
- SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1",
- mode_sort) < 0);
-}
-
-} /* anonymous namespace */
-
-#endif /* GDB_SELF_TEST */
-
-/* See cooked-index.h. */
-
-bool
-cooked_index_entry::matches (domain_search_flags kind) const
-{
- /* Just reject type declarations. */
- if ((flags & IS_TYPE_DECLARATION) != 0)
- return false;
-
- return tag_matches_domain (tag, kind, lang);
-}
-
-/* See cooked-index.h. */
-
-const char *
-cooked_index_entry::full_name (struct obstack *storage,
- cooked_index_full_name_flag name_flags,
- const char *default_sep) const
-{
- const char *local_name = ((name_flags & FOR_MAIN) != 0) ? name : canonical;
-
- if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr)
- return local_name;
-
- const char *sep = default_sep;
- switch (lang)
- {
- case language_cplus:
- case language_rust:
- case language_fortran:
- sep = "::";
- break;
-
- case language_ada:
- if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0)
- {
- sep = "__";
- break;
- }
- [[fallthrough]];
- case language_go:
- case language_d:
- sep = ".";
- break;
-
- default:
- if (sep == nullptr)
- return local_name;
- break;
- }
-
- /* The FOR_ADA_LINKAGE_NAME flag should only affect Ada entries, so
- disable it here if we don't need it. */
- if (lang != language_ada)
- name_flags &= ~FOR_ADA_LINKAGE_NAME;
-
- get_parent ()->write_scope (storage, sep, name_flags);
- obstack_grow0 (storage, local_name, strlen (local_name));
- return (const char *) obstack_finish (storage);
-}
-
-/* See cooked-index.h. */
-
-void
-cooked_index_entry::write_scope (struct obstack *storage,
- const char *sep,
- cooked_index_full_name_flag flags) const
-{
- if (get_parent () != nullptr)
- get_parent ()->write_scope (storage, sep, flags);
- /* When computing the Ada linkage name, the entry might not have
- been canonicalized yet, so use the 'name'. */
- const char *local_name = ((flags & (FOR_MAIN | FOR_ADA_LINKAGE_NAME)) != 0
- ? name
- : canonical);
- obstack_grow (storage, local_name, strlen (local_name));
- obstack_grow (storage, sep, strlen (sep));
-}
-
-/* See cooked-index.h. */
-
-cooked_index_entry *
-cooked_index_shard::create (sect_offset die_offset,
- enum dwarf_tag tag,
- cooked_index_flag flags,
- enum language lang,
- const char *name,
- cooked_index_entry_ref parent_entry,
- dwarf2_per_cu *per_cu)
-{
- if (tag == DW_TAG_module || tag == DW_TAG_namespace)
- flags &= ~IS_STATIC;
- else if (lang == language_cplus
- && (tag == DW_TAG_class_type
- || tag == DW_TAG_interface_type
- || tag == DW_TAG_structure_type
- || tag == DW_TAG_union_type
- || tag == DW_TAG_enumeration_type
- || tag == DW_TAG_enumerator))
- flags &= ~IS_STATIC;
- else if (tag_is_type (tag))
- flags |= IS_STATIC;
-
- return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
- lang, name, parent_entry,
- per_cu);
-}
-
-/* See cooked-index.h. */
-
-cooked_index_entry *
-cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag,
- cooked_index_flag flags, enum language lang,
- const char *name, cooked_index_entry_ref parent_entry,
- dwarf2_per_cu *per_cu)
-{
- cooked_index_entry *result = create (die_offset, tag, flags, lang, name,
- parent_entry, per_cu);
- m_entries.push_back (result);
-
- /* An explicitly-tagged main program should always override the
- implicit "main" discovery. */
- if ((flags & IS_MAIN) != 0)
- m_main = result;
- else if ((flags & IS_PARENT_DEFERRED) == 0
- && parent_entry.resolved == nullptr
- && m_main == nullptr
- && language_may_use_plain_main (lang)
- && strcmp (name, "main") == 0)
- m_main = result;
-
- return result;
-}
-
-/* See cooked-index.h. */
-
-void
-cooked_index_shard::handle_gnat_encoded_entry
- (cooked_index_entry *entry,
- htab_t gnat_entries,
- std::vector<cooked_index_entry *> &new_entries)
-{
- /* We decode Ada names in a particular way: operators and wide
- characters are left as-is. This is done to make name matching a
- bit simpler; and for wide characters, it means the choice of Ada
- source charset does not affect the indexer directly. */
- std::string canonical = ada_decode (entry->name, false, false, false);
- if (canonical.empty ())
- {
- entry->canonical = entry->name;
- return;
- }
- std::vector<std::string_view> names = split_name (canonical.c_str (),
- split_style::DOT_STYLE);
- std::string_view tail = names.back ();
- names.pop_back ();
-
- const cooked_index_entry *parent = nullptr;
- for (const auto &name : names)
- {
- uint32_t hashval = dwarf5_djb_hash (name);
- void **slot = htab_find_slot_with_hash (gnat_entries, &name,
- hashval, INSERT);
- /* CUs are processed in order, so we only need to check the most
- recent entry. */
- cooked_index_entry *last = (cooked_index_entry *) *slot;
- if (last == nullptr || last->per_cu != entry->per_cu)
- {
- const char *new_name = m_names.insert (name);
- last = create (entry->die_offset, DW_TAG_module,
- IS_SYNTHESIZED, language_ada, new_name, parent,
- entry->per_cu);
- last->canonical = last->name;
- new_entries.push_back (last);
- *slot = last;
- }
-
- parent = last;
- }
-
- entry->set_parent (parent);
- entry->canonical = m_names.insert (tail);
-}
-
-/* Hash a cooked index entry by name pointer value.
-
- We can use pointer equality here because names come from .debug_str, which
- will normally be unique-ified by the linker. Also, duplicates are relatively
- harmless -- they just mean a bit of extra memory is used. */
-
-struct cooked_index_entry_name_ptr_hash
-{
- using is_avalanching = void;
-
- std::uint64_t operator () (const cooked_index_entry *entry) const noexcept
- {
- return ankerl::unordered_dense::hash<const char *> () (entry->name);
- }
-};
-
-/* Compare cooked index entries by name pointer value. */
-
-struct cooked_index_entry_name_ptr_eq
-{
- bool operator () (const cooked_index_entry *a,
- const cooked_index_entry *b) const noexcept
- {
- return a->name == b->name;
- }
-};
-
-/* See cooked-index.h. */
-
-void
-cooked_index_shard::finalize (const parent_map_map *parent_maps)
-{
- gdb::unordered_set<const cooked_index_entry *,
- cooked_index_entry_name_ptr_hash,
- cooked_index_entry_name_ptr_eq> seen_names;
-
- auto hash_entry = [] (const void *e)
- {
- const cooked_index_entry *entry = (const cooked_index_entry *) e;
- return dwarf5_djb_hash (entry->canonical);
- };
-
- auto eq_entry = [] (const void *a, const void *b) -> int
- {
- const cooked_index_entry *ae = (const cooked_index_entry *) a;
- const std::string_view *sv = (const std::string_view *) b;
- return (strlen (ae->canonical) == sv->length ()
- && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
- };
-
- htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
- nullptr, xcalloc, xfree));
- std::vector<cooked_index_entry *> new_gnat_entries;
-
- for (cooked_index_entry *entry : m_entries)
- {
- if ((entry->flags & IS_PARENT_DEFERRED) != 0)
- {
- const cooked_index_entry *new_parent
- = parent_maps->find (entry->get_deferred_parent ());
- entry->resolve_parent (new_parent);
- }
-
- /* Note that this code must be kept in sync with
- language_requires_canonicalization. */
- gdb_assert (entry->canonical == nullptr);
- if ((entry->flags & IS_LINKAGE) != 0)
- entry->canonical = entry->name;
- else if (entry->lang == language_ada)
- {
- /* Newer versions of GNAT emit DW_TAG_module and use a
- hierarchical structure. In this case, we don't need to
- do any extra work. This can be detected by looking for a
- GNAT-encoded name. */
- if (strstr (entry->name, "__") == nullptr)
- {
- entry->canonical = entry->name;
-
- /* If the entry does not have a parent, then there's
- nothing extra to do here -- the entry itself is
- sufficient.
-
- However, if it does have a parent, we have to
- synthesize an entry with the full name. This is
- unfortunate, but it's necessary due to how some of
- the Ada name-lookup code currently works. For
- example, without this, ada_get_tsd_type will
- fail.
-
- Eventually it would be good to change the Ada lookup
- code, and then remove these entries (and supporting
- code in cooked_index_entry::full_name). */
- if (entry->get_parent () != nullptr)
- {
- const char *fullname
- = entry->full_name (&m_storage, FOR_ADA_LINKAGE_NAME);
- cooked_index_entry *linkage = create (entry->die_offset,
- entry->tag,
- (entry->flags
- | IS_LINKAGE
- | IS_SYNTHESIZED),
- language_ada,
- fullname,
- nullptr,
- entry->per_cu);
- linkage->canonical = fullname;
- new_gnat_entries.push_back (linkage);
- }
- }
- else
- handle_gnat_encoded_entry (entry, gnat_entries.get (),
- new_gnat_entries);
- }
- else if (entry->lang == language_cplus || entry->lang == language_c)
- {
- auto [it, inserted] = seen_names.insert (entry);
-
- if (inserted)
- {
- /* No entry with that name was present, compute the canonical
- name. */
- gdb::unique_xmalloc_ptr<char> canon_name
- = (entry->lang == language_cplus
- ? cp_canonicalize_string (entry->name)
- : c_canonicalize_name (entry->name));
- if (canon_name == nullptr)
- entry->canonical = entry->name;
- else
- entry->canonical = m_names.insert (std::move (canon_name));
- }
- else
- {
- /* An entry with that name was present, re-use its canonical
- name. */
- entry->canonical = (*it)->canonical;
- }
- }
- else
- entry->canonical = entry->name;
- }
-
- /* Make sure any new Ada entries end up in the results. This isn't
- done when creating these new entries to avoid invalidating the
- m_entries iterator used in the foreach above. */
- m_entries.insert (m_entries.end (), new_gnat_entries.begin (),
- new_gnat_entries.end ());
-
- m_entries.shrink_to_fit ();
- std::sort (m_entries.begin (), m_entries.end (),
- [] (const cooked_index_entry *a, const cooked_index_entry *b)
- {
- return *a < *b;
- });
-}
-
-/* See cooked-index.h. */
-
-cooked_index_shard::range
-cooked_index_shard::find (const std::string &name, bool completing) const
-{
- cooked_index_entry::comparison_mode mode = (completing
- ? cooked_index_entry::COMPLETE
- : cooked_index_entry::MATCH);
-
- auto lower = std::lower_bound (m_entries.cbegin (), m_entries.cend (), name,
- [=] (const cooked_index_entry *entry,
- const std::string &n)
- {
- return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) < 0;
- });
-
- auto upper = std::upper_bound (m_entries.cbegin (), m_entries.cend (), name,
- [=] (const std::string &n,
- const cooked_index_entry *entry)
- {
- return cooked_index_entry::compare (entry->canonical, n.c_str (), mode) > 0;
- });
-
- return range (lower, upper);
-}
-
-/* See cooked-index.h. */
-
-void
-cooked_index_worker::start ()
-{
- gdb::thread_pool::g_thread_pool->post_task ([this] ()
- {
- try
- {
- do_reading ();
- }
- catch (const gdb_exception &exc)
- {
- m_failed = exc;
- set (cooked_state::CACHE_DONE);
- }
-
- bfd_thread_cleanup ();
- });
-}
-
-/* See cooked-index.h. */
-
-bool
-cooked_index_worker::wait (cooked_state desired_state, bool allow_quit)
-{
- bool done;
-#if CXX_STD_THREAD
- {
- std::unique_lock<std::mutex> lock (m_mutex);
-
- /* This may be called from a non-main thread -- this functionality
- is needed for the index cache -- but in this case we require
- that the desired state already have been attained. */
- gdb_assert (is_main_thread () || desired_state <= m_state);
-
- while (desired_state > m_state)
- {
- if (allow_quit)
- {
- std::chrono::milliseconds duration { 15 };
- if (m_cond.wait_for (lock, duration) == std::cv_status::timeout)
- QUIT;
- }
- else
- m_cond.wait (lock);
- }
- done = m_state == cooked_state::CACHE_DONE;
- }
-#else
- /* Without threads, all the work is done immediately on the main
- thread, and there is never anything to wait for. */
- done = desired_state == cooked_state::CACHE_DONE;
-#endif /* CXX_STD_THREAD */
-
- /* Only the main thread is allowed to report complaints and the
- like. */
- if (!is_main_thread ())
- return false;
-
- if (m_reported)
- return done;
- m_reported = true;
-
- /* Emit warnings first, maybe they were emitted before an exception
- (if any) was thrown. */
- m_warnings.emit ();
-
- if (m_failed.has_value ())
- {
- /* do_reading failed -- report it. */
- exception_print (gdb_stderr, *m_failed);
- m_failed.reset ();
- return done;
- }
-
- /* Only show a given exception a single time. */
- gdb::unordered_set<gdb_exception> seen_exceptions;
- for (auto &one_result : m_results)
- {
- re_emit_complaints (std::get<1> (one_result));
- for (auto &one_exc : std::get<2> (one_result))
- if (seen_exceptions.insert (one_exc).second)
- exception_print (gdb_stderr, one_exc);
- }
-
- print_stats ();
-
- struct objfile *objfile = m_per_objfile->objfile;
- dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
- cooked_index *table
- = (gdb::checked_static_cast<cooked_index *>
- (per_bfd->index_table.get ()));
-
- auto_obstack temp_storage;
- enum language lang = language_unknown;
- const char *main_name = table->get_main_name (&temp_storage, &lang);
- if (main_name != nullptr)
- set_objfile_main_name (objfile, main_name, lang);
-
- /* dwarf_read_debug_printf ("Done building psymtabs of %s", */
- /* objfile_name (objfile)); */
-
- return done;
-}
-
-/* See cooked-index.h. */
-
-void
-cooked_index_worker::set (cooked_state desired_state)
-{
- gdb_assert (desired_state != cooked_state::INITIAL);
-
-#if CXX_STD_THREAD
- std::lock_guard<std::mutex> guard (m_mutex);
- gdb_assert (desired_state > m_state);
- m_state = desired_state;
- m_cond.notify_one ();
-#else
- /* Without threads, all the work is done immediately on the main
- thread, and there is never anything to do. */
-#endif /* CXX_STD_THREAD */
-}
-
-/* See cooked-index.h. */
-
-void
-cooked_index_worker::write_to_cache (const cooked_index *idx,
- deferred_warnings *warn) const
-{
- if (idx != nullptr)
- {
- /* Writing to the index cache may cause a warning to be emitted.
- See PR symtab/30837. This arranges to capture all such
- warnings. This is safe because we know the deferred_warnings
- object isn't in use by any other thread at this point. */
- scoped_restore_warning_hook defer (warn);
- m_cache_store.store ();
- }
-}
-
cooked_index::cooked_index (cooked_index_worker_up &&worker)
: m_state (std::move (worker))
{
@@ -746,12 +78,10 @@ cooked_index::wait (cooked_state desired_state, bool allow_quit)
}
void
-cooked_index::set_contents (std::vector<cooked_index_shard_up> &&shards,
- deferred_warnings *warn,
- const parent_map_map *parent_maps)
+cooked_index::set_contents ()
{
gdb_assert (m_shards.empty ());
- m_shards = std::move (shards);
+ m_shards = m_state->release_shards ();
m_state->set (cooked_state::MAIN_AVAILABLE);
@@ -760,16 +90,17 @@ cooked_index::set_contents (std::vector<cooked_index_shard_up> &&shards,
finalization. However, that would take a slot in the global
thread pool, and if enough such tasks were submitted at once, it
would cause a livelock. */
- gdb::task_group finalizers ([this, warn] ()
+ gdb::task_group finalizers ([this] ()
{
m_state->set (cooked_state::FINALIZED);
- m_state->write_to_cache (index_for_writing (), warn);
+ m_state->write_to_cache (index_for_writing ());
m_state->set (cooked_state::CACHE_DONE);
});
for (auto &shard : m_shards)
{
auto this_shard = shard.get ();
+ const parent_map_map *parent_maps = m_state->get_parent_map_map ();
finalizers.add_task ([=] () { this_shard->finalize (parent_maps); });
}
@@ -994,10 +325,6 @@ void _initialize_cooked_index ();
void
_initialize_cooked_index ()
{
-#if GDB_SELF_TEST
- selftests::register_test ("cooked_index_entry::compare", test_compare);
-#endif
-
add_cmd ("wait-for-index-cache", class_maintenance,
maintenance_wait_for_index_cache, _("\
Wait until all pending writes to the index cache have completed.\n\
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index 56c84bd..384938e 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -20,490 +20,16 @@
#ifndef GDB_DWARF2_COOKED_INDEX_H
#define GDB_DWARF2_COOKED_INDEX_H
-#include "dwarf2.h"
-#include "dwarf2/types.h"
+#include "dwarf2/cooked-index-entry.h"
#include "symtab.h"
-#include "hashtab.h"
#include "quick-symbol.h"
-#include "gdbsupport/gdb_obstack.h"
#include "addrmap.h"
-#include "gdbsupport/iterator-range.h"
#include "dwarf2/mapped-index.h"
#include "dwarf2/read.h"
#include "dwarf2/parent-map.h"
#include "gdbsupport/range-chain.h"
-#include "gdbsupport/string-set.h"
-#include "complaints.h"
-
-#if CXX_STD_THREAD
-#include <mutex>
-#include <condition_variable>
-#endif /* CXX_STD_THREAD */
-
-struct dwarf2_per_cu;
-struct dwarf2_per_bfd;
-struct index_cache_store_context;
-struct cooked_index_entry;
-
-/* Flags that describe an entry in the index. */
-enum cooked_index_flag_enum : unsigned char
-{
- /* True if this entry is the program's "main". */
- IS_MAIN = 1,
- /* True if this entry represents a "static" object. */
- IS_STATIC = 2,
- /* True if this entry uses the linkage name. */
- IS_LINKAGE = 4,
- /* True if this entry is just for the declaration of a type, not the
- definition. */
- IS_TYPE_DECLARATION = 8,
- /* True is parent_entry.deferred has a value rather than parent_entry
- .resolved. */
- IS_PARENT_DEFERRED = 16,
- /* True if this entry was synthesized by gdb (as opposed to coming
- directly from the DWARF). */
- IS_SYNTHESIZED = 32,
-};
-DEF_ENUM_FLAGS_TYPE (enum cooked_index_flag_enum, cooked_index_flag);
-
-/* Flags used when requesting the full name of an entry. */
-enum cooked_index_full_name_enum : unsigned char
-{
- /* Set when requesting the name of "main". See the method for the
- full description. */
- FOR_MAIN = 1,
- /* Set when requesting the linkage name for an Ada entry. */
- FOR_ADA_LINKAGE_NAME = 2,
-};
-DEF_ENUM_FLAGS_TYPE (enum cooked_index_full_name_enum, cooked_index_full_name_flag);
-
-/* Type representing either a resolved or deferred cooked_index_entry. */
-
-union cooked_index_entry_ref
-{
- cooked_index_entry_ref (parent_map::addr_type deferred_)
- {
- deferred = deferred_;
- }
-
- cooked_index_entry_ref (const cooked_index_entry *resolved_)
- {
- resolved = resolved_;
- }
-
- const cooked_index_entry *resolved;
- parent_map::addr_type deferred;
-};
-
-/* Return a string representation of FLAGS. */
-
-std::string to_string (cooked_index_flag flags);
-
-/* Return true if LANG requires canonicalization. This is used
- primarily to work around an issue computing the name of "main".
- This function must be kept in sync with
- cooked_index_shard::finalize. */
-
-extern bool language_requires_canonicalization (enum language lang);
-
-/* A cooked_index_entry represents a single item in the index. Note
- that two entries can be created for the same DIE -- one using the
- name, and another one using the linkage name, if any.
-
- This is an "open" class and the members are all directly
- accessible. It is read-only after the index has been fully read
- and processed. */
-struct cooked_index_entry : public allocate_on_obstack<cooked_index_entry>
-{
- cooked_index_entry (sect_offset die_offset_, enum dwarf_tag tag_,
- cooked_index_flag flags_,
- enum language lang_, const char *name_,
- cooked_index_entry_ref parent_entry_,
- dwarf2_per_cu *per_cu_)
- : name (name_),
- tag (tag_),
- flags (flags_),
- lang (lang_),
- die_offset (die_offset_),
- per_cu (per_cu_),
- m_parent_entry (parent_entry_)
- {
- }
-
- /* Return true if this entry matches SEARCH_FLAGS. */
- bool matches (block_search_flags search_flags) const
- {
- /* Just reject type declarations. */
- if ((flags & IS_TYPE_DECLARATION) != 0)
- return false;
-
- if ((search_flags & SEARCH_STATIC_BLOCK) != 0
- && (flags & IS_STATIC) != 0)
- return true;
- if ((search_flags & SEARCH_GLOBAL_BLOCK) != 0
- && (flags & IS_STATIC) == 0)
- return true;
- return false;
- }
-
- /* Return true if this entry matches KIND. */
- bool matches (domain_search_flags kind) const;
-
- /* Construct the fully-qualified name of this entry and return a
- pointer to it. If allocation is needed, it will be done on
- STORAGE.
-
- FLAGS affects the result. If the FOR_MAIN flag is set, we are
- computing the name of the "main" entry -- one marked
- DW_AT_main_subprogram. This matters for avoiding name
- canonicalization and also a related race (if "main" computation
- is done during finalization).
-
- If the FOR_ADA_LINKAGE_NAME flag is set, then Ada-language
- symbols will have their "linkage-style" name computed. The
- default is source-style.
-
- If the language doesn't prescribe a separator, one can be
- specified using DEFAULT_SEP. */
- const char *full_name (struct obstack *storage,
- cooked_index_full_name_flag name_flags = 0,
- const char *default_sep = nullptr) const;
-
- /* Comparison modes for the 'compare' function. See the function
- for a description. */
- enum comparison_mode
- {
- MATCH,
- SORT,
- COMPLETE,
- };
-
- /* Compare two strings, case-insensitively. Return -1 if STRA is
- less than STRB, 0 if they are equal, and 1 if STRA is greater.
-
- When comparing, '<' is considered to be less than all other
- printable characters. This ensures that "t<x>" sorts before
- "t1", which is necessary when looking up "t". This '<' handling
- is to ensure that certain C++ lookups work correctly. It is
- inexact, and applied regardless of the search language, but this
- is ok because callers of this code do more precise filtering
- according to their needs. This is also why using a
- case-insensitive comparison works even for languages that are
- case sensitive.
-
- MODE controls how the comparison proceeds.
-
- MODE==SORT is used when sorting and the only special '<' handling
- that it does is to ensure that '<' sorts before all other
- printable characters. This ensures that the resulting ordering
- will be binary-searchable.
-
- MODE==MATCH is used when searching for a symbol. In this case,
- STRB must always be the search name, and STRA must be the name in
- the index that is under consideration. In compare mode, early
- termination of STRB may match STRA -- for example, "t<int>" and
- "t" will be considered to be equal. (However, if A=="t" and
- B=="t<int>", then this will not consider them as equal.)
-
- MODE==COMPLETE is used when searching for a symbol for
- completion. In this case, STRB must always be the search name,
- and STRA must be the name in the index that is under
- consideration. In completion mode, early termination of STRB
- always results in a match. */
- static int compare (const char *stra, const char *strb,
- comparison_mode mode);
-
- /* Compare two entries by canonical name. */
- bool operator< (const cooked_index_entry &other) const
- {
- return compare (canonical, other.canonical, SORT) < 0;
- }
-
- /* Set parent entry to PARENT. */
- void set_parent (const cooked_index_entry *parent)
- {
- gdb_assert ((flags & IS_PARENT_DEFERRED) == 0);
- m_parent_entry.resolved = parent;
- }
-
- /* Resolve deferred parent entry to PARENT. */
- void resolve_parent (const cooked_index_entry *parent)
- {
- gdb_assert ((flags & IS_PARENT_DEFERRED) != 0);
- flags = flags & ~IS_PARENT_DEFERRED;
- m_parent_entry.resolved = parent;
- }
-
- /* Return parent entry. */
- const cooked_index_entry *get_parent () const
- {
- gdb_assert ((flags & IS_PARENT_DEFERRED) == 0);
- return m_parent_entry.resolved;
- }
-
- /* Return deferred parent entry. */
- parent_map::addr_type get_deferred_parent () const
- {
- gdb_assert ((flags & IS_PARENT_DEFERRED) != 0);
- return m_parent_entry.deferred;
- }
-
- /* The name as it appears in DWARF. This always points into one of
- the mapped DWARF sections. Note that this may be the name or the
- linkage name -- two entries are created for DIEs which have both
- attributes. */
- const char *name;
- /* The canonical name. This may be equal to NAME. */
- const char *canonical = nullptr;
- /* The DWARF tag. */
- enum dwarf_tag tag;
- /* Any flags attached to this entry. */
- cooked_index_flag flags;
- /* The language of this symbol. */
- ENUM_BITFIELD (language) lang : LANGUAGE_BITS;
- /* The offset of this DIE. */
- sect_offset die_offset;
- /* The CU from which this entry originates. */
- dwarf2_per_cu *per_cu;
-
-private:
-
- /* A helper method for full_name. Emits the full scope of this
- object, followed by the separator, to STORAGE. If this entry has
- a parent, its write_scope method is called first. See full_name
- for a description of the FLAGS parameter. */
- void write_scope (struct obstack *storage, const char *sep,
- cooked_index_full_name_flag flags) const;
-
- /* The parent entry. This is NULL for top-level entries.
- Otherwise, it points to the parent entry, such as a namespace or
- class. */
- cooked_index_entry_ref m_parent_entry;
-};
-
-class cooked_index;
-
-/* An index of interesting DIEs. This is "cooked", in contrast to a
- mapped .debug_names or .gdb_index, which are "raw". An entry in
- the index is of type cooked_index_entry.
-
- Operations on the index are described below. They are chosen to
- make it relatively simple to implement the symtab "quick"
- methods. */
-class cooked_index_shard
-{
-public:
- cooked_index_shard () = default;
- DISABLE_COPY_AND_ASSIGN (cooked_index_shard);
-
- /* Create a new cooked_index_entry and register it with this object.
- Entries are owned by this object. The new item is returned. */
- cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
- cooked_index_flag flags, enum language lang,
- const char *name,
- cooked_index_entry_ref parent_entry,
- dwarf2_per_cu *per_cu);
-
- /* Install a new fixed addrmap from the given mutable addrmap. */
- void install_addrmap (addrmap_mutable *map)
- {
- gdb_assert (m_addrmap == nullptr);
- m_addrmap = new (&m_storage) addrmap_fixed (&m_storage, map);
- }
-
- friend class cooked_index;
-
- /* A simple range over part of m_entries. */
- typedef iterator_range<std::vector<cooked_index_entry *>::const_iterator>
- range;
-
- /* Return a range of all the entries. */
- range all_entries () const
- {
- return { m_entries.cbegin (), m_entries.cend () };
- }
-
- /* Look up an entry by name. Returns a range of all matching
- results. If COMPLETING is true, then a larger range, suitable
- for completion, will be returned. */
- range find (const std::string &name, bool completing) const;
-
-private:
-
- /* Return the entry that is believed to represent the program's
- "main". This will return NULL if no such entry is available. */
- const cooked_index_entry *get_main () const
- {
- return m_main;
- }
-
- /* Look up ADDR in the address map, and return either the
- corresponding CU, or nullptr if the address could not be
- found. */
- dwarf2_per_cu *lookup (unrelocated_addr addr)
- {
- if (m_addrmap == nullptr)
- return nullptr;
-
- return (static_cast<dwarf2_per_cu *> (m_addrmap->find ((CORE_ADDR) addr)));
- }
-
- /* Create a new cooked_index_entry and register it with this object.
- Entries are owned by this object. The new item is returned. */
- cooked_index_entry *create (sect_offset die_offset,
- enum dwarf_tag tag,
- cooked_index_flag flags,
- enum language lang,
- const char *name,
- cooked_index_entry_ref parent_entry,
- dwarf2_per_cu *per_cu);
-
- /* When GNAT emits mangled ("encoded") names in the DWARF, and does
- not emit the module structure, we still need this structuring to
- do lookups. This function recreates that information for an
- existing entry, modifying ENTRY as appropriate. Any new entries
- are added to NEW_ENTRIES. */
- void handle_gnat_encoded_entry
- (cooked_index_entry *entry, htab_t gnat_entries,
- std::vector<cooked_index_entry *> &new_entries);
-
- /* Finalize the index. This should be called a single time, when
- the index has been fully populated. It enters all the entries
- into the internal table and fixes up all missing parent links.
- This may be invoked in a worker thread. */
- void finalize (const parent_map_map *parent_maps);
-
- /* Storage for the entries. */
- auto_obstack m_storage;
- /* List of all entries. */
- std::vector<cooked_index_entry *> m_entries;
- /* If we found an entry with 'is_main' set, store it here. */
- cooked_index_entry *m_main = nullptr;
- /* The addrmap. This maps address ranges to dwarf2_per_cu objects. */
- addrmap_fixed *m_addrmap = nullptr;
- /* Storage for canonical names. */
- gdb::string_set m_names;
-};
-
-using cooked_index_shard_up = std::unique_ptr<cooked_index_shard>;
-
-/* The possible states of the index. See the explanatory comment
- before cooked_index for more details. */
-enum class cooked_state
-{
- /* The default state. This is not a valid argument to 'wait'. */
- INITIAL,
- /* The initial scan has completed. The name of "main" is now
- available (if known). The addrmaps are usable now.
- Finalization has started but is not complete. */
- MAIN_AVAILABLE,
- /* Finalization has completed. This means the index is fully
- available for queries. */
- FINALIZED,
- /* Writing to the index cache has finished. */
- CACHE_DONE,
-};
-
-/* An object of this type controls the scanning of the DWARF. It
- schedules the worker tasks and tracks the current state. Once
- scanning is done, this object is discarded.
-
- This is an abstract base class that defines the basic behavior of
- scanners. Separate concrete implementations exist for scanning
- .debug_names and .debug_info. */
-
-class cooked_index_worker
-{
-public:
-
- explicit cooked_index_worker (dwarf2_per_objfile *per_objfile)
- : m_per_objfile (per_objfile),
- m_cache_store (global_index_cache, per_objfile->per_bfd)
- { }
- virtual ~cooked_index_worker ()
- { }
- DISABLE_COPY_AND_ASSIGN (cooked_index_worker);
-
- /* Start reading. */
- void start ();
-
- /* Wait for a particular state to be achieved. If ALLOW_QUIT is
- true, then the loop will check the QUIT flag. Normally this
- method may only be called from the main thread; however, it can
- be called from a worker thread provided that the desired state
- has already been attained. (This oddity is used by the index
- cache writer.) */
- bool wait (cooked_state desired_state, bool allow_quit);
-
-protected:
-
- /* Let cooked_index call the 'set' and 'write_to_cache' methods. */
- friend class cooked_index;
-
- /* Set the current state. */
- void set (cooked_state desired_state);
-
- /* Write to the index cache. */
- void write_to_cache (const cooked_index *idx,
- deferred_warnings *warn) const;
-
- /* Helper function that does the work of reading. This must be able
- to be run in a worker thread without problems. */
- virtual void do_reading () = 0;
-
- /* A callback that can print stats, if needed. This is called when
- transitioning to the 'MAIN_AVAILABLE' state. */
- virtual void print_stats ()
- { }
-
- /* Each thread returns a tuple holding a cooked index, any collected
- complaints, a vector of errors that should be printed, and a
- parent map.
-
- The errors are retained because GDB's I/O system is not
- thread-safe. run_on_main_thread could be used, but that would
- mean the messages are printed after the prompt, which looks
- weird. */
- using result_type = std::tuple<cooked_index_shard_up,
- complaint_collection,
- std::vector<gdb_exception>,
- parent_map>;
-
- /* The per-objfile object. */
- dwarf2_per_objfile *m_per_objfile;
- /* Result of each worker task. */
- std::vector<result_type> m_results;
- /* Any warnings emitted. This is not in 'result_type' because (for
- the time being at least), it's only needed in do_reading, not in
- every worker. Note that deferred_warnings uses gdb_stderr in its
- constructor, and this should only be done from the main thread.
- This is enforced in the cooked_index_worker constructor. */
- deferred_warnings m_warnings;
-
- /* A map of all parent maps. Used during finalization to fix up
- parent relationships. */
- parent_map_map m_all_parents_map;
-
-#if CXX_STD_THREAD
- /* Current state of this object. */
- cooked_state m_state = cooked_state::INITIAL;
- /* Mutex and condition variable used to synchronize. */
- std::mutex m_mutex;
- std::condition_variable m_cond;
-#endif /* CXX_STD_THREAD */
- /* This flag indicates whether any complaints or exceptions that
- arose during scanning have been reported by 'wait'. This may
- only be modified on the main thread. */
- bool m_reported = false;
- /* If set, an exception occurred during reading; in this case the
- scanning is stopped and this exception will later be reported by
- the 'wait' method. */
- std::optional<gdb_exception> m_failed;
- /* An object used to write to the index cache. */
- index_cache_store_context m_cache_store;
-};
-
-using cooked_index_worker_up = std::unique_ptr<cooked_index_worker>;
+#include "dwarf2/cooked-index-shard.h"
+#include "dwarf2/cooked-index-worker.h"
/* The main index of DIEs.
@@ -515,6 +41,14 @@ using cooked_index_worker_up = std::unique_ptr<cooked_index_worker>;
possible. This combination should help hide the effort from the
user to the maximum possible degree.
+ There are a number of different objects involved in this process.
+ Most of them are temporary -- they are created to handle different
+ phases of scanning, then discarded when possible. The "steady
+ state" objects are index itself (cooked_index, below), which holds
+ the entries (cooked_index_entry), and the implementation of the
+ "quick" API (e.g., cooked_index_functions, though there are
+ other variants).
+
. Main Thread | Worker Threads
============================================================
. dwarf2_initialize_objfile
@@ -546,6 +80,7 @@ using cooked_index_worker_up = std::unique_ptr<cooked_index_worker>;
. v
. maybe write to index cache
. state = CACHE_DONE
+ . ~cooked_index_worker
.
.
. if main thread calls...
@@ -570,14 +105,8 @@ public:
void start_reading () override;
/* Called by cooked_index_worker to set the contents of this index
- and transition to the MAIN_AVAILABLE state. WARN is used to
- collect any warnings that may arise when writing to the cache.
- PARENT_MAPS is used when resolving pending parent links.
- PARENT_MAPS may be NULL if there are no IS_PARENT_DEFERRED
- entries in VEC. */
- void set_contents (std::vector<cooked_index_shard_up> &&vec,
- deferred_warnings *warn,
- const parent_map_map *parent_maps);
+ and transition to the MAIN_AVAILABLE state. */
+ void set_contents ();
/* A range over a vector of subranges. */
using range = range_chain<cooked_index_shard::range>;
diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c
index 3b80cd6..1f3a235 100644
--- a/gdb/dwarf2/cooked-indexer.c
+++ b/gdb/dwarf2/cooked-indexer.c
@@ -18,12 +18,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "dwarf2/cooked-indexer.h"
-#include "dwarf2/cooked-index-storage.h"
+#include "dwarf2/cooked-index-worker.h"
#include "dwarf2/error.h"
/* See cooked-indexer.h. */
-cooked_indexer::cooked_indexer (cooked_index_storage *storage,
+cooked_indexer::cooked_indexer (cooked_index_worker_result *storage,
dwarf2_per_cu *per_cu, enum language language)
: m_index_storage (storage),
m_per_cu (per_cu),
@@ -109,7 +109,7 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader,
cutu_reader *result = m_index_storage->get_reader (per_cu);
if (result == nullptr)
{
- cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false,
+ cutu_reader new_reader (*per_cu, *per_objfile, nullptr, nullptr, false,
language_minimal,
&m_index_storage->get_abbrev_table_cache ());
diff --git a/gdb/dwarf2/cooked-indexer.h b/gdb/dwarf2/cooked-indexer.h
index 93626a9..904c55f 100644
--- a/gdb/dwarf2/cooked-indexer.h
+++ b/gdb/dwarf2/cooked-indexer.h
@@ -20,13 +20,13 @@
#ifndef GDB_DWARF2_COOKED_INDEXER_H
#define GDB_DWARF2_COOKED_INDEXER_H
-#include "dwarf2/cooked-index.h"
+#include "dwarf2/cooked-index-entry.h"
#include "dwarf2/parent-map.h"
#include "dwarf2/types.h"
#include <variant>
struct abbrev_info;
-struct cooked_index_storage;
+struct cooked_index_worker_result;
struct cutu_reader;
struct dwarf2_per_cu;
struct dwarf2_per_objfile;
@@ -36,7 +36,7 @@ struct dwarf2_per_objfile;
class cooked_indexer
{
public:
- cooked_indexer (cooked_index_storage *storage, dwarf2_per_cu *per_cu,
+ cooked_indexer (cooked_index_worker_result *storage, dwarf2_per_cu *per_cu,
enum language language);
DISABLE_COPY_AND_ASSIGN (cooked_indexer);
@@ -103,7 +103,7 @@ private:
bool fully);
/* The storage object, where the results are kept. */
- cooked_index_storage *m_index_storage;
+ cooked_index_worker_result *m_index_storage;
/* The CU that we are reading on behalf of. This object might be
asked to index one CU but to treat the results as if they come
from some including CU; in this case the including CU would be
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 7c12c0d..8f66694 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1784,6 +1784,7 @@ dwarf2_compile_property_to_c (string_file *stream,
CORE_ADDR pc,
struct symbol *sym)
{
+#if defined (HAVE_COMPILE)
const dwarf2_property_baton *baton = prop->baton ();
const gdb_byte *data;
size_t size;
@@ -1810,6 +1811,9 @@ dwarf2_compile_property_to_c (string_file *stream,
gdbarch, registers_used,
per_cu->addr_size (),
data, data + size, per_cu, per_objfile);
+#else
+ gdb_assert_not_reached ("Compile support was disabled");
+#endif
}
/* Compute the correct symbol_needs_kind value for the location
@@ -3852,6 +3856,7 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream,
std::vector<bool> &registers_used,
CORE_ADDR pc, const char *result_name)
{
+#if defined (HAVE_COMPILE)
struct dwarf2_locexpr_baton *dlbaton
= (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (sym);
unsigned int addr_size = dlbaton->per_cu->addr_size ();
@@ -3863,6 +3868,9 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream,
sym, pc, gdbarch, registers_used, addr_size,
dlbaton->data, dlbaton->data + dlbaton->size,
dlbaton->per_cu, dlbaton->per_objfile);
+#else
+ gdb_assert_not_reached ("Compile support was disabled");
+#endif
}
/* The set of location functions used with the DWARF-2 expression
@@ -4088,6 +4096,7 @@ loclist_generate_c_location (struct symbol *sym, string_file *stream,
std::vector<bool> &registers_used,
CORE_ADDR pc, const char *result_name)
{
+#if defined (HAVE_COMPILE)
struct dwarf2_loclist_baton *dlbaton
= (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (sym);
unsigned int addr_size = dlbaton->per_cu->addr_size ();
@@ -4103,6 +4112,9 @@ loclist_generate_c_location (struct symbol *sym, string_file *stream,
data, data + size,
dlbaton->per_cu,
dlbaton->per_objfile);
+#else
+ gdb_assert_not_reached ("Compile support was disabled");
+#endif
}
/* The set of location functions used with the DWARF-2 expression
diff --git a/gdb/dwarf2/parent-map.c b/gdb/dwarf2/parent-map.c
index d029a76..6f290c1 100644
--- a/gdb/dwarf2/parent-map.c
+++ b/gdb/dwarf2/parent-map.c
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "dwarf2/cooked-index.h"
+#include "dwarf2/cooked-index-entry.h"
#include "dwarf2/read.h"
#include "dwarf2/parent-map.h"
diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c
index edac713..96a8ad3 100644
--- a/gdb/dwarf2/read-debug-names.c
+++ b/gdb/dwarf2/read-debug-names.c
@@ -114,11 +114,12 @@ struct mapped_debug_names_reader
gdb::unordered_map<ULONGEST, index_val> abbrev_map;
- /* Even though the scanning of .debug_names and creation of the cooked index
- entries is done serially, we create multiple shards so that the
- finalization step can be parallelized. The shards are filled in a round
- robin fashion. */
- std::vector<cooked_index_shard_up> shards;
+ /* Even though the scanning of .debug_names and creation of the
+ cooked index entries is done serially, we create multiple shards
+ so that the finalization step can be parallelized. The shards
+ are filled in a round robin fashion. It's convenient to use a
+ result object rather than an actual shard. */
+ std::vector<cooked_index_worker_result> indices;
/* Next shard to insert an entry in. */
int next_shard = 0;
@@ -290,11 +291,11 @@ mapped_debug_names_reader::scan_one_entry (const char *name,
if (per_cu != nullptr)
{
*result
- = shards[next_shard]->add (die_offset, (dwarf_tag) indexval.dwarf_tag,
+ = indices[next_shard].add (die_offset, (dwarf_tag) indexval.dwarf_tag,
flags, lang, name, nullptr, per_cu);
++next_shard;
- if (next_shard == shards.size ())
+ if (next_shard == indices.size ())
next_shard = 0;
entry_pool_offsets_to_entries.emplace (offset_in_entry_pool, *result);
@@ -414,29 +415,31 @@ void
cooked_index_worker_debug_names::do_reading ()
{
complaint_interceptor complaint_handler;
- std::vector<gdb_exception> exceptions;
+
try
{
m_map.scan_all_names ();
}
- catch (const gdb_exception &exc)
+ catch (gdb_exception &exc)
{
- exceptions.push_back (std::move (exc));
+ /* Arbitrarily put all exceptions into the first result. */
+ m_map.indices[0].note_error (std::move (exc));
}
- m_results.emplace_back (nullptr,
- complaint_handler.release (),
- std::move (exceptions),
- parent_map ());
-
- dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
- cooked_index *table
- = (gdb::checked_static_cast<cooked_index *>
- (per_bfd->index_table.get ()));
+ bool first = true;
+ for (auto &iter : m_map.indices)
+ {
+ if (first)
+ {
+ iter.done_reading (complaint_handler.release ());
+ first = false;
+ }
+ else
+ iter.done_reading ({});
+ }
- /* Note that this code never uses IS_PARENT_DEFERRED, so it is safe
- to pass nullptr here. */
- table->set_contents (std::move (m_map.shards), &m_warnings, nullptr);
+ m_results = std::move (m_map.indices);
+ done_reading ();
bfd_thread_cleanup ();
}
@@ -838,24 +841,26 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
}
per_bfd->debug_aranges.read (per_objfile->objfile);
- addrmap_mutable addrmap;
+
+ /* There is a single address map for the whole index (coming from
+ .debug_aranges). We only need to install it into a single shard
+ for it to get searched by cooked_index. So, we make the first
+ result object here, so we can store the addrmap, then move it
+ into place later. */
+ cooked_index_worker_result first;
deferred_warnings warnings;
read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
- &addrmap, &warnings);
+ first.get_addrmap (), &warnings);
warnings.emit ();
const auto n_workers
= std::max<std::size_t> (gdb::thread_pool::g_thread_pool->thread_count (),
1);
- /* Create as many index shard as there are worker threads. */
- for (int i = 0; i < n_workers; ++i)
- map.shards.emplace_back (std::make_unique<cooked_index_shard> ());
-
- /* There is a single address map for the whole index (coming from
- .debug_aranges). We only need to install it into a single shard for it to
- get searched by cooked_index. */
- map.shards[0]->install_addrmap (&addrmap);
+ /* Create as many index shard as there are worker threads,
+ preserving the first one. */
+ map.indices.push_back (std::move (first));
+ map.indices.resize (n_workers);
auto cidn = (std::make_unique<cooked_index_worker_debug_names>
(per_objfile, std::move (map)));
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 8875e97..71fd352 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -32,7 +32,7 @@
#include "dwarf2/aranges.h"
#include "dwarf2/attribute.h"
#include "dwarf2/comp-unit-head.h"
-#include "dwarf2/cooked-index-storage.h"
+#include "dwarf2/cooked-index-worker.h"
#include "dwarf2/cooked-indexer.h"
#include "dwarf2/cu.h"
#include "dwarf2/index-cache.h"
@@ -728,7 +728,7 @@ show_dwarf_synchronous (struct ui_file *file, int from_tty,
/* local function prototypes */
static void build_type_psymtabs_reader (cutu_reader *reader,
- cooked_index_storage *storage);
+ cooked_index_worker_result *storage);
static void var_decode_location (struct attribute *attr,
struct symbol *sym,
@@ -1791,7 +1791,7 @@ dw2_get_file_names (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile)
if (this_cu->files_read)
return this_cu->file_names;
- cutu_reader reader (this_cu, per_objfile, nullptr,
+ cutu_reader reader (*this_cu, *per_objfile, nullptr,
per_objfile->get_cu (this_cu), true, language_minimal,
nullptr);
if (!reader.is_dummy ())
@@ -2710,8 +2710,7 @@ cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section,
void
cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
die_info *stub_comp_unit_die,
- const char *stub_comp_dir,
- abbrev_table_up *result_dwo_abbrev_table)
+ const char *stub_comp_dir)
{
dwarf2_per_objfile *per_objfile = cu->per_objfile;
dwarf2_per_cu *per_cu = cu->per_cu;
@@ -2829,10 +2828,18 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
}
dwo_abbrev_section->read (objfile);
- *result_dwo_abbrev_table
+ m_dwo_abbrev_table
= abbrev_table::read (dwo_abbrev_section, cu->header.abbrev_sect_off);
this->init_cu_die_reader (cu, section, dwo_unit->dwo_file,
- result_dwo_abbrev_table->get ());
+ m_dwo_abbrev_table.get ());
+
+ /* Skip dummy compilation units. */
+ if (m_info_ptr >= begin_info_ptr + dwo_unit->length
+ || peek_abbrev_code (abfd, m_info_ptr) == 0)
+ {
+ m_dummy_p = true;
+ return;
+ }
/* Read in the die, filling in the attributes from the stub. This
has the benefit of simplifying the rest of the code - all the
@@ -2841,11 +2848,6 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
m_top_level_die
= this->read_toplevel_die (gdb::make_array_view (attributes,
next_attr_idx));
-
- /* Skip dummy compilation units. */
- if (m_info_ptr >= begin_info_ptr + dwo_unit->length
- || peek_abbrev_code (abfd, m_info_ptr) == 0)
- m_dummy_p = true;
}
/* Return the signature of the compile unit, if found. In DWARF 4 and before,
@@ -2864,8 +2866,12 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
}
/* Subroutine of cutu_reader to simplify it.
- Look up the DWO unit specified by COMP_UNIT_DIE of THIS_CU.
- Returns NULL if the specified DWO unit cannot be found. */
+ Look up the DWO unit specified by COMP_UNIT_DIE of CU.
+
+ DWO_NAME is the name (DW_AT_dwo_name) of the DWO unit already read from
+ COMP_UNIT_DIE.
+
+ Returns nullptr if the specified DWO unit cannot be found. */
static struct dwo_unit *
lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name)
@@ -2883,8 +2889,6 @@ lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name)
gdb_assert (cu != NULL);
- /* Yeah, we look dwo_name up again, but it simplifies the code. */
- dwo_name = dwarf2_dwo_name (comp_unit_die, cu);
comp_dir = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
if (per_cu->is_debug_types)
@@ -2946,8 +2950,7 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu,
could share abbrev tables. */
read_cutu_die_from_dwo (cu, sig_type->dwo_unit, NULL /* stub_comp_unit_die */,
- sig_type->dwo_unit->dwo_file->comp_dir,
- &m_dwo_abbrev_table);
+ sig_type->dwo_unit->dwo_file->comp_dir);
prepare_one_comp_unit (cu, pretend_language);
}
@@ -2961,16 +2964,16 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu,
If EXISTING_CU is non-NULL, then use it. Otherwise, a new CU is
allocated. */
-cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
- dwarf2_per_objfile *per_objfile,
+cutu_reader::cutu_reader (dwarf2_per_cu &this_cu,
+ dwarf2_per_objfile &per_objfile,
const struct abbrev_table *abbrev_table,
dwarf2_cu *existing_cu,
bool skip_partial,
enum language pretend_language,
- const abbrev_table_cache *cache)
+ const abbrev_table_cache *abbrev_cache)
{
- struct objfile *objfile = per_objfile->objfile;
- struct dwarf2_section_info *section = this_cu->section;
+ struct objfile *objfile = per_objfile.objfile;
+ struct dwarf2_section_info *section = this_cu.section;
bfd *abfd = section->get_bfd_owner ();
const gdb_byte *begin_info_ptr;
struct signatured_type *sig_type = NULL;
@@ -2982,17 +2985,17 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
if (dwarf_die_debug)
gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n",
- this_cu->is_debug_types ? "type" : "comp",
- sect_offset_str (this_cu->sect_off));
+ this_cu.is_debug_types ? "type" : "comp",
+ sect_offset_str (this_cu.sect_off));
/* If we're reading a TU directly from a DWO file, including a virtual DWO
file (instead of going through the stub), short-circuit all of this. */
- if (this_cu->reading_dwo_directly)
+ if (this_cu.reading_dwo_directly)
{
/* Narrow down the scope of possibilities to have to understand. */
- gdb_assert (this_cu->is_debug_types);
+ gdb_assert (this_cu.is_debug_types);
gdb_assert (abbrev_table == NULL);
- init_tu_and_read_dwo_dies (this_cu, per_objfile, existing_cu,
+ init_tu_and_read_dwo_dies (&this_cu, &per_objfile, existing_cu,
pretend_language);
return;
}
@@ -3001,9 +3004,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
section->read (objfile);
begin_info_ptr = m_info_ptr
- = section->buffer + to_underlying (this_cu->sect_off);
+ = section->buffer + to_underlying (this_cu.sect_off);
- abbrev_section = get_abbrev_section_for_cu (this_cu);
+ abbrev_section = get_abbrev_section_for_cu (&this_cu);
dwarf2_cu *cu;
@@ -3027,9 +3030,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
indexer. This assert is avoided in this case because (1) it
is irrelevant, and (2) the get_cu method is not
thread-safe. */
- gdb_assert (cache != nullptr
- || per_objfile->get_cu (this_cu) == nullptr);
- m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile);
+ gdb_assert (abbrev_cache != nullptr
+ || per_objfile.get_cu (&this_cu) == nullptr);
+ m_new_cu = std::make_unique<dwarf2_cu> (&this_cu, &per_objfile);
cu = m_new_cu.get ();
}
@@ -3041,43 +3044,43 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
}
else
{
- if (this_cu->is_debug_types)
+ if (this_cu.is_debug_types)
{
m_info_ptr
- = read_and_check_comp_unit_head (per_objfile, &cu->header, section,
+ = read_and_check_comp_unit_head (&per_objfile, &cu->header, section,
abbrev_section, m_info_ptr,
rcuh_kind::TYPE);
/* Since per_cu is the first member of struct signatured_type,
we can go from a pointer to one to a pointer to the other. */
- sig_type = (struct signatured_type *) this_cu;
+ sig_type = (struct signatured_type *) &this_cu;
gdb_assert (sig_type->signature == cu->header.signature);
gdb_assert (sig_type->type_offset_in_tu
== cu->header.type_cu_offset_in_tu);
- gdb_assert (this_cu->sect_off == cu->header.sect_off);
+ gdb_assert (this_cu.sect_off == cu->header.sect_off);
/* LENGTH has not been set yet for type units if we're
using .gdb_index. */
- this_cu->set_length (cu->header.get_length_with_initial ());
+ this_cu.set_length (cu->header.get_length_with_initial ());
/* Establish the type offset that can be used to lookup the type. */
sig_type->type_offset_in_section =
- this_cu->sect_off + to_underlying (sig_type->type_offset_in_tu);
+ this_cu.sect_off + to_underlying (sig_type->type_offset_in_tu);
}
else
{
m_info_ptr
- = read_and_check_comp_unit_head (per_objfile, &cu->header, section,
+ = read_and_check_comp_unit_head (&per_objfile, &cu->header, section,
abbrev_section, m_info_ptr,
rcuh_kind::COMPILE);
- gdb_assert (this_cu->sect_off == cu->header.sect_off);
- this_cu->set_length (cu->header.get_length_with_initial ());
+ gdb_assert (this_cu.sect_off == cu->header.sect_off);
+ this_cu.set_length (cu->header.get_length_with_initial ());
}
}
/* Skip dummy compilation units. */
- if (m_info_ptr >= begin_info_ptr + this_cu->length ()
+ if (m_info_ptr >= begin_info_ptr + this_cu.length ()
|| peek_abbrev_code (abfd, m_info_ptr) == 0)
m_dummy_p = true;
else
@@ -3089,9 +3092,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
else
{
- if (cache != nullptr)
- abbrev_table = cache->find (abbrev_section,
- cu->header.abbrev_sect_off);
+ if (abbrev_cache != nullptr)
+ abbrev_table = abbrev_cache->find (abbrev_section,
+ cu->header.abbrev_sect_off);
if (abbrev_table == nullptr)
{
abbrev_section->read (objfile);
@@ -3129,14 +3132,13 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
{
complaint (_("compilation unit with DW_AT_GNU_dwo_name"
" has children (offset %s) [in module %s]"),
- sect_offset_str (this_cu->sect_off),
+ sect_offset_str (this_cu.sect_off),
bfd_get_filename (abfd));
}
dwo_unit = lookup_dwo_unit (cu, m_top_level_die, dwo_name);
if (dwo_unit != NULL)
- read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr,
- &m_dwo_abbrev_table);
+ read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr);
else
{
/* Yikes, we couldn't find the rest of the DIE, we only have
@@ -3165,65 +3167,57 @@ cutu_reader::release_cu ()
return std::move (m_new_cu);
}
-/* Read CU/TU THIS_CU but do not follow DW_AT_GNU_dwo_name (DW_AT_dwo_name)
- if present. DWO_FILE, if non-NULL, is the DWO file to read (the caller is
- assumed to have already done the lookup to find the DWO file).
-
- The caller is required to fill in THIS_CU->section, THIS_CU->offset, and
- THIS_CU->is_debug_types, but nothing else.
-
- We fill in THIS_CU->length.
+/* This constructor exists for the special case of reading many units in a row
+ from a given known DWO file.
- THIS_CU->cu is always freed when done.
- This is done in order to not leave THIS_CU->cu in a state where we have
- to care whether it refers to the "main" CU or the DWO CU.
+ THIS_CU is a special dwarf2_per_cu to represent where to read the unit from,
+ in the DWO file. The caller is required to fill THIS_CU::SECTION,
+ THIS_CU::SECT_OFF, and THIS_CU::IS_DEBUG_TYPES. This constructor will fill
+ in the length. THIS_CU::SECTION must point to a section from the DWO file,
+ which is normally not the case for regular dwarf2_per_cu uses.
- When parent_cu is passed, it is used to provide a default value for
- str_offsets_base and addr_base from the parent. */
+ PARENT_CU is the CU created when reading the skeleton unit, and is used to
+ provide a default value for str_offsets_base and addr_base. */
-cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
- dwarf2_per_objfile *per_objfile,
- enum language pretend_language,
- struct dwarf2_cu *parent_cu,
- struct dwo_file *dwo_file)
+cutu_reader::cutu_reader (dwarf2_per_cu &this_cu,
+ dwarf2_per_objfile &per_objfile,
+ language pretend_language, dwarf2_cu &parent_cu,
+ dwo_file &dwo_file)
{
- struct objfile *objfile = per_objfile->objfile;
- struct dwarf2_section_info *section = this_cu->section;
+ struct objfile *objfile = per_objfile.objfile;
+ struct dwarf2_section_info *section = this_cu.section;
bfd *abfd = section->get_bfd_owner ();
- gdb_assert (parent_cu != nullptr);
- gdb_assert (dwo_file != nullptr);
-
if (dwarf_die_debug)
gdb_printf (gdb_stdlog, "Reading %s unit at offset %s\n",
- this_cu->is_debug_types ? "type" : "comp",
- sect_offset_str (this_cu->sect_off));
+ this_cu.is_debug_types ? "type" : "comp",
+ sect_offset_str (this_cu.sect_off));
- gdb_assert (per_objfile->get_cu (this_cu) == nullptr);
+ gdb_assert (per_objfile.get_cu (&this_cu) == nullptr);
- dwarf2_section_info *abbrev_section = &dwo_file->sections.abbrev;
+ dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
/* This is cheap if the section is already read in. */
section->read (objfile);
- m_new_cu = std::make_unique<dwarf2_cu> (this_cu, per_objfile);
+ m_new_cu = std::make_unique<dwarf2_cu> (&this_cu, &per_objfile);
- m_info_ptr = section->buffer + to_underlying (this_cu->sect_off);
+ m_info_ptr = section->buffer + to_underlying (this_cu.sect_off);
const gdb_byte *begin_info_ptr = m_info_ptr;
m_info_ptr
- = read_and_check_comp_unit_head (per_objfile, &m_new_cu->header, section,
+ = read_and_check_comp_unit_head (&per_objfile, &m_new_cu->header, section,
abbrev_section, m_info_ptr,
- (this_cu->is_debug_types
+ (this_cu.is_debug_types
? rcuh_kind::TYPE
: rcuh_kind::COMPILE));
- m_new_cu->str_offsets_base = parent_cu->str_offsets_base;
- m_new_cu->addr_base = parent_cu->addr_base;
+ m_new_cu->str_offsets_base = parent_cu.str_offsets_base;
+ m_new_cu->addr_base = parent_cu.addr_base;
- this_cu->set_length (m_new_cu->header.get_length_with_initial ());
+ this_cu.set_length (m_new_cu->header.get_length_with_initial ());
/* Skip dummy compilation units. */
- if (m_info_ptr >= begin_info_ptr + this_cu->length ()
+ if (m_info_ptr >= begin_info_ptr + this_cu.length ()
|| peek_abbrev_code (abfd, m_info_ptr) == 0)
m_dummy_p = true;
else
@@ -3233,7 +3227,7 @@ cutu_reader::cutu_reader (dwarf2_per_cu *this_cu,
= abbrev_table::read (abbrev_section,
m_new_cu->header.abbrev_sect_off);
- this->init_cu_die_reader (m_new_cu.get (), section, dwo_file,
+ this->init_cu_die_reader (m_new_cu.get (), section, &dwo_file,
m_abbrev_table_holder.get ());
m_top_level_die = this->read_toplevel_die ();
}
@@ -3295,12 +3289,12 @@ get_type_unit_group_key (struct dwarf2_cu *cu, const struct attribute *stmt_list
static void
process_psymtab_comp_unit (dwarf2_per_cu *this_cu,
dwarf2_per_objfile *per_objfile,
- cooked_index_storage *storage)
+ cooked_index_worker_result *storage)
{
cutu_reader *reader = storage->get_reader (this_cu);
if (reader == nullptr)
{
- cutu_reader new_reader (this_cu, per_objfile, nullptr, nullptr, false,
+ cutu_reader new_reader (*this_cu, *per_objfile, nullptr, nullptr, false,
language_minimal,
&storage->get_abbrev_table_cache ());
@@ -3332,7 +3326,7 @@ process_psymtab_comp_unit (dwarf2_per_cu *this_cu,
static void
build_type_psymtabs_reader (cutu_reader *reader,
- cooked_index_storage *storage)
+ cooked_index_worker_result *storage)
{
struct dwarf2_cu *cu = reader->cu ();
dwarf2_per_cu *per_cu = cu->per_cu;
@@ -3385,7 +3379,7 @@ struct tu_abbrev_offset
static void
build_type_psymtabs (dwarf2_per_objfile *per_objfile,
- cooked_index_storage *storage)
+ cooked_index_worker_result *storage)
{
struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
abbrev_table_up abbrev_table;
@@ -3447,7 +3441,7 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile,
++tu_stats->nr_uniq_abbrev_tables;
}
- cutu_reader reader (tu.sig_type, per_objfile,
+ cutu_reader reader (*tu.sig_type, *per_objfile,
abbrev_table.get (), nullptr, false,
language_minimal);
if (!reader.is_dummy ())
@@ -3482,7 +3476,7 @@ print_tu_stats (dwarf2_per_objfile *per_objfile)
static void
process_skeletonless_type_unit (dwo_unit *dwo_unit,
dwarf2_per_objfile *per_objfile,
- cooked_index_storage *storage)
+ cooked_index_worker_result *storage)
{
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
@@ -3501,7 +3495,7 @@ process_skeletonless_type_unit (dwo_unit *dwo_unit,
fill_in_sig_entry_from_dwo_entry (per_objfile, *sig_type_it, dwo_unit);
/* This does the job that build_type_psymtabs would have done. */
- cutu_reader reader (*sig_type_it, per_objfile, nullptr, nullptr, false,
+ cutu_reader reader (**sig_type_it, *per_objfile, nullptr, nullptr, false,
language_minimal);
if (!reader.is_dummy ())
build_type_psymtabs_reader (&reader, storage);
@@ -3513,7 +3507,7 @@ process_skeletonless_type_unit (dwo_unit *dwo_unit,
static void
process_skeletonless_type_units (dwarf2_per_objfile *per_objfile,
- cooked_index_storage *storage)
+ cooked_index_worker_result *storage)
{
/* Skeletonless TUs in DWP files without .gdb_index is not supported yet. */
if (get_dwp_file (per_objfile) == nullptr)
@@ -3559,7 +3553,7 @@ private:
/* After the last DWARF-reading task has finished, this function
does the remaining work to finish the scan. */
- void done_reading ();
+ void done_reading () override;
/* An iterator for the comp units. */
using unit_iterator = std::vector<dwarf2_per_cu_up>::iterator;
@@ -3573,12 +3567,13 @@ private:
/* A storage object for "leftovers" -- see the 'start' method, but
essentially things not parsed during the normal CU parsing
passes. */
- cooked_index_storage m_index_storage;
+ cooked_index_worker_result m_index_storage;
};
void
-cooked_index_worker_debug_info::process_cus (size_t task_number, unit_iterator first,
- unit_iterator end)
+cooked_index_worker_debug_info::process_cus (size_t task_number,
+ unit_iterator first,
+ unit_iterator end)
{
SCOPE_EXIT { bfd_thread_cleanup (); };
@@ -3586,7 +3581,7 @@ cooked_index_worker_debug_info::process_cus (size_t task_number, unit_iterator f
complaint_interceptor complaint_handler;
std::vector<gdb_exception> errors;
- cooked_index_storage thread_storage;
+ cooked_index_worker_result thread_storage;
for (auto inner = first; inner != end; ++inner)
{
dwarf2_per_cu *per_cu = inner->get ();
@@ -3597,43 +3592,24 @@ cooked_index_worker_debug_info::process_cus (size_t task_number, unit_iterator f
}
catch (gdb_exception &except)
{
- errors.push_back (std::move (except));
+ thread_storage.note_error (std::move (except));
}
}
- m_results[task_number] = result_type (thread_storage.release (),
- complaint_handler.release (),
- std::move (errors),
- thread_storage.release_parent_map ());
+ thread_storage.done_reading (complaint_handler.release ());
+ m_results[task_number] = std::move (thread_storage);
}
void
cooked_index_worker_debug_info::done_reading ()
{
- /* Only handle the scanning results here. Complaints and exceptions
- can only be dealt with on the main thread. */
- std::vector<cooked_index_shard_up> shards;
-
- for (auto &one_result : m_results)
- {
- shards.push_back (std::move (std::get<0> (one_result)));
- m_all_parents_map.add_map (std::get<3> (one_result));
- }
-
/* This has to wait until we read the CUs, we need the list of DWOs. */
process_skeletonless_type_units (m_per_objfile, &m_index_storage);
- shards.push_back (m_index_storage.release ());
- shards.shrink_to_fit ();
-
- m_all_parents_map.add_map (m_index_storage.release_parent_map ());
+ m_results.push_back (std::move (m_index_storage));
- dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
- cooked_index *table
- = (gdb::checked_static_cast<cooked_index *>
- (per_bfd->index_table.get ()));
- table->set_contents (std::move (shards), &m_warnings,
- &m_all_parents_map);
+ /* Call into the base class. */
+ cooked_index_worker::done_reading ();
}
void
@@ -4223,7 +4199,7 @@ load_full_comp_unit (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile,
gdb_assert (! this_cu->is_debug_types);
gdb_assert (per_objfile->get_cu (this_cu) == nullptr);
- cutu_reader reader (this_cu, per_objfile, nullptr, nullptr, skip_partial,
+ cutu_reader reader (*this_cu, *per_objfile, nullptr, nullptr, skip_partial,
pretend_language);
if (reader.is_dummy ())
return;
@@ -6358,8 +6334,8 @@ create_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file)
/* The length of the CU gets set by the cutu_reader just below. */
dwarf2_per_cu per_cu (per_bfd, &section, sect_off, 0 /* length */,
false /* is_dwz */);
- cutu_reader reader (&per_cu, per_objfile, language_minimal,
- cu, &dwo_file);
+ cutu_reader reader (per_cu, *per_objfile, language_minimal,
+ *cu, dwo_file);
info_ptr += per_cu.length ();
@@ -15323,7 +15299,7 @@ dwarf2_read_addr_index (dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile,
}
else
{
- cutu_reader reader (per_cu, per_objfile, nullptr, nullptr, false,
+ cutu_reader reader (*per_cu, *per_objfile, nullptr, nullptr, false,
language_minimal);
addr_base = reader.cu ()->addr_base;
addr_size = reader.cu ()->header.addr_size;
@@ -18823,7 +18799,7 @@ read_signatured_type (signatured_type *sig_type,
gdb_assert (sig_type->is_debug_types);
gdb_assert (per_objfile->get_cu (sig_type) == nullptr);
- cutu_reader reader (sig_type, per_objfile, nullptr, nullptr, false,
+ cutu_reader reader (*sig_type, *per_objfile, nullptr, nullptr, false,
language_minimal);
if (!reader.is_dummy ())
@@ -19336,7 +19312,7 @@ dwarf2_per_cu::ensure_lang (dwarf2_per_objfile *per_objfile)
/* Constructing this object will set the language as a side
effect. */
- cutu_reader reader (this, per_objfile, nullptr, per_objfile->get_cu (this),
+ cutu_reader reader (*this, *per_objfile, nullptr, per_objfile->get_cu (this),
true, language_minimal, nullptr);
}
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index ba2dd07..b13e42d 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -921,19 +921,19 @@ class cutu_reader
{
public:
- cutu_reader (dwarf2_per_cu *this_cu,
- dwarf2_per_objfile *per_objfile,
+ cutu_reader (dwarf2_per_cu &this_cu,
+ dwarf2_per_objfile &per_objfile,
const struct abbrev_table *abbrev_table,
dwarf2_cu *existing_cu,
bool skip_partial,
enum language pretend_language,
- const abbrev_table_cache *cache = nullptr);
+ const abbrev_table_cache *abbrev_cache = nullptr);
- cutu_reader (dwarf2_per_cu *this_cu,
- dwarf2_per_objfile *per_objfile,
+ cutu_reader (dwarf2_per_cu &this_cu,
+ dwarf2_per_objfile &per_objfile,
enum language pretend_language,
- struct dwarf2_cu *parent_cu,
- struct dwo_file *dwo_file);
+ struct dwarf2_cu &parent_cu,
+ struct dwo_file &dwo_file);
DISABLE_COPY_AND_ASSIGN (cutu_reader);
@@ -1003,8 +1003,7 @@ private:
void read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit,
die_info *stub_comp_unit_die,
- const char *stub_comp_dir,
- abbrev_table_up *result_dwo_abbrev_table);
+ const char *stub_comp_dir);
void prepare_one_comp_unit (struct dwarf2_cu *cu,
enum language pretend_language);
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 5be3118..ed664bc 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -898,7 +898,7 @@ elf_gnu_ifunc_resolve_name (const char *name, CORE_ADDR *addr_p)
return false;
}
-/* Call STT_GNU_IFUNC - a function returning addresss of a real function to
+/* Call STT_GNU_IFUNC - a function returning address of a real function to
call. PC is theSTT_GNU_IFUNC resolving function entry. The value returned
is the entry point of the resolved STT_GNU_IFUNC target function to call.
*/
@@ -1062,8 +1062,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags,
const struct elfinfo *ei)
{
bfd *synth_abfd, *abfd = objfile->obfd.get ();
- long symcount = 0, dynsymcount = 0, synthcount, storage_needed;
- asymbol **symbol_table = NULL, **dyn_symbol_table = NULL;
+ long dynsymcount = 0, synthcount;
+ asymbol **dyn_symbol_table = NULL;
asymbol *synthsyms;
symtab_create_debug_printf ("reading minimal symbols of objfile %s",
@@ -1087,32 +1087,16 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags,
/* Process the normal ELF symbol table first. */
- storage_needed = bfd_get_symtab_upper_bound (objfile->obfd.get ());
- if (storage_needed < 0)
- error (_("Can't read symbols from %s: %s"),
- bfd_get_filename (objfile->obfd.get ()),
- bfd_errmsg (bfd_get_error ()));
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (objfile->obfd.get ());
- if (storage_needed > 0)
- {
- /* Memory gets permanently referenced from ABFD after
- bfd_canonicalize_symtab so it must not get freed before ABFD gets. */
-
- symbol_table = (asymbol **) bfd_alloc (abfd, storage_needed);
- symcount = bfd_canonicalize_symtab (objfile->obfd.get (), symbol_table);
-
- if (symcount < 0)
- error (_("Can't read symbols from %s: %s"),
- bfd_get_filename (objfile->obfd.get ()),
- bfd_errmsg (bfd_get_error ()));
-
- elf_symtab_read (reader, objfile, ST_REGULAR, symcount, symbol_table,
- false);
- }
+ elf_symtab_read (reader, objfile, ST_REGULAR, symbol_table.size (),
+ symbol_table.data (), false);
/* Add the dynamic symbols. */
- storage_needed = bfd_get_dynamic_symtab_upper_bound (objfile->obfd.get ());
+ long storage_needed
+ = bfd_get_dynamic_symtab_upper_bound (objfile->obfd.get ());
if (storage_needed > 0)
{
@@ -1157,7 +1141,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags,
/* Add synthetic symbols - for instance, names for any PLT entries. */
- synthcount = bfd_get_synthetic_symtab (synth_abfd, symcount, symbol_table,
+ synthcount = bfd_get_synthetic_symtab (synth_abfd, symbol_table.size (),
+ symbol_table.data (),
dynsymcount, dyn_symbol_table,
&synthsyms);
if (synthcount > 0)
diff --git a/gdb/frame-base.h b/gdb/frame-base.h
index 8436929..ba12c70 100644
--- a/gdb/frame-base.h
+++ b/gdb/frame-base.h
@@ -32,7 +32,7 @@ struct regcache;
the NEXT frame's register unwind method, to determine the address
of THIS frame's `base'.
- The exact meaning of `base' is highly dependant on the type of the
+ The exact meaning of `base' is highly dependent on the type of the
debug info. It is assumed that dwarf2, stabs, ... will each
provide their own methods.
diff --git a/gdb/frame.c b/gdb/frame.c
index 2fb06a0..88560b8 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2325,7 +2325,22 @@ get_prev_frame_always_1 (const frame_info_ptr &this_frame)
until we have unwound all the way down to the previous non-inline
frame. */
if (get_frame_type (this_frame) == INLINE_FRAME)
- return get_prev_frame_maybe_check_cycle (this_frame);
+ {
+ frame_info_ptr fi = get_prev_frame_maybe_check_cycle (this_frame);
+
+ /* If this_frame is the current frame, then compute and stash its frame
+ id so that the cycle check in get_prev_frame_maybe_check_cycle works
+ correctly in the case where inline frame 0 has been duplicated.
+
+ The this_id.p check is required to avoid recursion as computing the
+ frame id results in a call to inline_frame_this_id which calls back
+ into get_prev_frame_always. */
+ if (this_frame->level == 0
+ && this_frame->this_id.p != frame_id_status::COMPUTING)
+ get_frame_id (this_frame);
+
+ return fi;
+ }
/* If this_frame is the current frame, then compute and stash its
frame id prior to fetching and computing the frame id of the
diff --git a/gdb/frame.h b/gdb/frame.h
index e207c71..5dd0d16 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -586,7 +586,7 @@ void set_current_sal_from_frame (const frame_info_ptr &);
the old get_frame_base method was not sufficient.
get_frame_base_address: get_frame_locals_address:
- get_frame_args_address: A set of high-level debug-info dependant
+ get_frame_args_address: A set of high-level debug-info dependent
addresses that fall within the frame. These addresses almost
certainly will not match the stack address part of a frame ID (as
returned by get_frame_base).
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
index 2ef77a2..8b8b661 100644
--- a/gdb/ft32-tdep.c
+++ b/gdb/ft32-tdep.c
@@ -310,7 +310,7 @@ ft32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
return sal.end;
}
}
- /* No useable line symbol. Use result of prologue parsing method. */
+ /* No usable line symbol. Use result of prologue parsing method. */
return plg_end;
}
}
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 8380c53..1a57b3c 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -143,6 +143,13 @@ struct gdb_bfd_data
/* Table of all the bfds this bfd has included. */
std::vector<gdb_bfd_ref_ptr> included_bfds;
+ /* This is used by gdb_bfd_canonicalize_symtab to hold the symbols
+ returned by canonicalization. */
+ std::optional<gdb::def_vector<asymbol *>> symbol_table;
+ /* If an error occurred while canonicalizing the symtab, this holds
+ the error message. */
+ std::string symbol_error;
+
/* The registry. */
registry<bfd> registry_fields;
@@ -1177,6 +1184,54 @@ gdb_bfd_errmsg (bfd_error_type error_tag, char **matching)
return ret;
}
+/* See gdb_bfd.h. */
+
+gdb::array_view<asymbol *>
+gdb_bfd_canonicalize_symtab (bfd *abfd, bool should_throw)
+{
+ struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
+
+ if (!gdata->symbol_table.has_value ())
+ {
+ /* Ensure it exists. */
+ gdb::def_vector<asymbol *> &symbol_table
+ = gdata->symbol_table.emplace ();
+
+ long storage_needed = bfd_get_symtab_upper_bound (abfd);
+ if (storage_needed < 0)
+ gdata->symbol_error = bfd_errmsg (bfd_get_error ());
+ else if (storage_needed > 0)
+ {
+ symbol_table.resize (storage_needed / sizeof (asymbol *));
+ long number_of_symbols
+ = bfd_canonicalize_symtab (abfd, symbol_table.data ());
+ if (number_of_symbols < 0)
+ {
+ symbol_table.clear ();
+ gdata->symbol_error = bfd_errmsg (bfd_get_error ());
+ }
+ }
+ }
+
+ if (!gdata->symbol_error.empty ())
+ {
+ if (should_throw)
+ error (_("Cannot parse symbols of \"%s\": %s"),
+ bfd_get_filename (abfd), gdata->symbol_error.c_str ());
+ return {};
+ }
+
+ gdb::def_vector<asymbol *> &symbol_table = *gdata->symbol_table;
+ if (symbol_table.empty ())
+ return {};
+
+ /* bfd_canonicalize_symtab adds a trailing NULL, but don't include
+ this in the array view. */
+ gdb_assert (symbol_table.back () == nullptr);
+ return gdb::make_array_view (symbol_table.data (),
+ symbol_table.size () - 1);
+}
+
/* Implement the 'maint info bfd' command. */
static void
diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
index d35f2d6..7830bf3 100644
--- a/gdb/gdb_bfd.h
+++ b/gdb/gdb_bfd.h
@@ -274,4 +274,16 @@ extern std::string gdb_bfd_errmsg (bfd_error_type error_tag, char **matching);
extern void gdb_bfd_init ();
+/* A wrapper for bfd_canonicalize_symtab that caches the result. This
+ is important to avoid excess memory use on repeated calls. See
+ PR gdb/32758. bfd_canonicalize_symtab should not be called directly
+ by other code in gdb.
+
+ When SHOULD_THROW is true (the default), this will throw an
+ exception if symbols could not be read. When SHOULD_THROW is
+ false, an empty view is returned instead. */
+
+extern gdb::array_view<asymbol *> gdb_bfd_canonicalize_symtab
+ (bfd *abfd, bool should_throw = true);
+
#endif /* GDB_GDB_BFD_H */
diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c
index 27b17d17..8f42557 100644
--- a/gdb/gdbarch-selftests.c
+++ b/gdb/gdbarch-selftests.c
@@ -127,6 +127,9 @@ register_to_value_test (struct gdbarch *gdbarch)
static void
register_name_test (struct gdbarch *gdbarch)
{
+ if (selftest_skip_warning_arch (gdbarch))
+ return;
+
scoped_mock_context<test_target_ops> mockctx (gdbarch);
/* Track the number of times each register name appears. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 786b720..f179151 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -210,7 +210,7 @@ gdbarch_tdep (struct gdbarch *gdbarch)
information obtained from INFO.ABFD or the global defaults.
The ARCHES parameter is a linked list (sorted most recently used)
- of all the previously created architures for this architecture
+ of all the previously created architectures for this architecture
family. The (possibly NULL) ARCHES->gdbarch can used to access
values from the previously selected architecture for this
architecture family.
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 6cffd86..ff1cdc6 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -70,10 +70,10 @@ extern bool debug_threads;
you want. */
enum thread_state
{
- /* In the frontend's perpective, the thread is stopped. */
+ /* In the frontend's perspective, the thread is stopped. */
THREAD_STOPPED,
- /* In the frontend's perpective, the thread is running. */
+ /* In the frontend's perspective, the thread is running. */
THREAD_RUNNING,
/* The thread is listed, but known to have exited. We keep it
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index b51c4d2..70d66a5 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -1178,7 +1178,7 @@ gnuv3_get_type_from_type_info (struct value *type_info_ptr)
{
/* We have to parse the type name, since in general there is not a
symbol for a type. This is somewhat bogus since there may be a
- mis-parse. Another approach might be to re-use the demangler's
+ mis-parse. Another approach might be to reuse the demangler's
internal form to reconstruct the type somehow. */
std::string type_name = gnuv3_get_typename_from_type_info (type_info_ptr);
expression_up expr (parse_expression (type_name.c_str ()));
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 8453366..7852f56 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -697,7 +697,7 @@ go32_nat_target::create_inferior (const char *exec_file,
"not enough memory.\n"));
/* Parse the command line and create redirections. */
- if (strpbrk (args, "<>"))
+ if (strpbrk (args, "<>") != nullptr)
{
if (redir_cmdline_parse (args, &child_cmd) == 0)
args = child_cmd.command;
diff --git a/gdb/gstack-1.in b/gdb/gstack-1.in
index 5e41329..25339d9 100755
--- a/gdb/gstack-1.in
+++ b/gdb/gstack-1.in
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# Copyright (C) 2024 Free Software Foundation, Inc.
+# Copyright (C) 2024-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
@@ -22,8 +22,8 @@
GDB=${GDB:-$(command -v gdb)}
GDBARGS=${GDBARGS:-}
AWK=${AWK:-}
-PKGVERSION=@PKGVERSION@
-VERSION=@VERSION@
+PKGVERSION="@PKGVERSION@"
+VERSION="@VERSION@"
# Find an appropriate awk interpreter if one was not specified
# via the environment.
@@ -132,7 +132,7 @@ EOF
)
# Run GDB and remove some unwanted noise.
-"$GDB" --quiet -nx --readnever $GDBARGS <<EOF |
+"$GDB" --quiet -nx $GDBARGS <<EOF |
set width 0
set height 0
set pagination no
diff --git a/gdb/h8300-tdep.c b/gdb/h8300-tdep.c
index a845900..6cffd06 100644
--- a/gdb/h8300-tdep.c
+++ b/gdb/h8300-tdep.c
@@ -541,7 +541,7 @@ h8300_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
/* Found a line number, use it as end of prologue. */
return sal.end;
- /* No useable line symbol. Use prologue parsing method. */
+ /* No usable line symbol. Use prologue parsing method. */
h8300_init_frame_cache (gdbarch, &cache);
return h8300_analyze_prologue (gdbarch, func_addr, func_end, &cache);
}
diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c
index f43a5e7..f9723ce 100644
--- a/gdb/hppa-linux-tdep.c
+++ b/gdb/hppa-linux-tdep.c
@@ -322,7 +322,7 @@ static const struct frame_unwind_legacy hppa_linux_sigtramp_frame_unwind (
/* Attempt to find (and return) the global pointer for the given
function.
- This is a rather nasty bit of code searchs for the .dynamic section
+ This rather nasty bit of code searches for the .dynamic section
in the objfile corresponding to the pc of the function we're trying
to call. Once it finds the addresses at which the .dynamic section
lives in the child process, it scans the Elf32_Dyn entries for a
diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c
index d9f4067..3b3ca49 100644
--- a/gdb/i386-fbsd-nat.c
+++ b/gdb/i386-fbsd-nat.c
@@ -92,7 +92,7 @@ i386_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
/* There is no i386_fxsave_supplies or i386_xsave_supplies.
Instead, the earlier register sets return early if the request
- was for a specific register that was already satisified to avoid
+ was for a specific register that was already satisfied to avoid
fetching the FPU/XSAVE state unnecessarily. */
#ifdef PT_GETXSTATE_INFO
@@ -171,7 +171,7 @@ i386_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
/* There is no i386_fxsave_supplies or i386_xsave_supplies.
Instead, the earlier register sets return early if the request
- was for a specific register that was already satisified to avoid
+ was for a specific register that was already satisfied to avoid
fetching the FPU/XSAVE state unnecessarily. */
#ifdef PT_GETXSTATE_INFO
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 3fb1c17..2b7bd2b 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -484,15 +484,15 @@ i386_canonicalize_syscall (int syscall)
SYSCALL_MAP (settimeofday);
SYSCALL_MAP_RENAME (getgroups, gdb_sys_getgroups16);
SYSCALL_MAP_RENAME (setgroups, gdb_sys_setgroups16);
- SYSCALL_MAP_RENAME (select, gdb_old_select);
+ SYSCALL_MAP_RENAME (select, gdb_sys_old_select);
SYSCALL_MAP (symlink);
SYSCALL_MAP_RENAME (oldlstat, gdb_sys_lstat);
SYSCALL_MAP (readlink);
SYSCALL_MAP (uselib);
SYSCALL_MAP (swapon);
SYSCALL_MAP (reboot);
- SYSCALL_MAP_RENAME (readdir, gdb_old_readdir);
- SYSCALL_MAP_RENAME (mmap, gdb_old_mmap);
+ SYSCALL_MAP_RENAME (readdir, gdb_sys_old_readdir);
+ SYSCALL_MAP_RENAME (mmap, gdb_sys_old_mmap);
SYSCALL_MAP (munmap);
SYSCALL_MAP (truncate);
SYSCALL_MAP (ftruncate);
diff --git a/gdb/i386-sol2-nat.c b/gdb/i386-sol2-nat.c
index 20ca9d6..665756a 100644
--- a/gdb/i386-sol2-nat.c
+++ b/gdb/i386-sol2-nat.c
@@ -25,7 +25,7 @@
#include "target.h"
#include "procfs.h"
-/* This file provids the (temporary) glue between the Solaris x86
+/* This file provides the (temporary) glue between the Solaris x86
target dependent code and the machine independent SVR4 /proc
support. */
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 1d6d592..f14a0d3 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2322,7 +2322,7 @@ static const struct frame_unwind_legacy i386_epilogue_frame_unwind (
/* These trampolines are used on cross x86 targets, when taking the
address of a nested function. When executing these trampolines,
no stack frame is set up, so we are in a similar situation as in
- epilogues and i386_epilogue_frame_this_id can be re-used. */
+ epilogues and i386_epilogue_frame_this_id can be reused. */
/* Static chain passed in register. */
@@ -5015,7 +5015,7 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r,
case 0x5e: /* VDIV[P|S][S|D] */
case 0x5f: /* VMAX[P|S][S|D] */
{
- /* vpbroadcast and arithmethic operations are differentiated
+ /* vpbroadcast and arithmetic operations are differentiated
by map_select, but it doesn't change the recording mechanics. */
i386_record_modrm (ir);
int reg_offset = ir->reg + vex_r * 8;
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 11375d5..00b48af 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -596,7 +596,7 @@ fetch_instruction (CORE_ADDR addr, ia64_instruction_type *it, long long *instr)
If we would like to store the whole bundle to SHADOW_CONTENTS we would have
to store already the base address (`address & ~0x0f') into PLACED_ADDRESS.
In such case there is no other place where to store
- SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know
+ SLOTNUM (`address & 0x0f', value in the range <0..2>). We need to know
SLOTNUM in ia64_memory_remove_breakpoint.
There is one special case where we need to be extra careful:
@@ -3111,7 +3111,7 @@ static const struct frame_unwind_legacy ia64_libunwind_sigtramp_frame_unwind (
ia64_libunwind_sigtramp_frame_sniffer
);
-/* Set of libunwind callback acccessor functions. */
+/* Set of libunwind callback accessor functions. */
unw_accessors_t ia64_unw_accessors =
{
ia64_find_proc_info_x,
@@ -3124,7 +3124,7 @@ unw_accessors_t ia64_unw_accessors =
/* get_proc_name */
};
-/* Set of special libunwind callback acccessor functions specific for accessing
+/* Set of special libunwind callback accessor functions specific for accessing
the rse registers. At the top of the stack, we want libunwind to figure out
how to read r32 - r127. Though usually they are found sequentially in
memory starting from $bof, this is not always true. */
@@ -3415,7 +3415,7 @@ slot_alignment_is_next_even (struct type *t)
/* Attempt to find (and return) the global pointer for the given
function.
- This is a rather nasty bit of code searchs for the .dynamic section
+ This rather nasty bit of code searches for the .dynamic section
in the objfile corresponding to the pc of the function we're trying
to call. Once it finds the addresses at which the .dynamic section
lives in the child process, it scans the Elf64_Dyn entries for a
diff --git a/gdb/ia64-vms-tdep.c b/gdb/ia64-vms-tdep.c
index 20308c7..ef8f42d 100644
--- a/gdb/ia64-vms-tdep.c
+++ b/gdb/ia64-vms-tdep.c
@@ -118,7 +118,7 @@ ia64_vms_get_dyn_info_list (unw_addr_space_t as,
return -UNW_ENOINFO;
}
-/* Set of libunwind callback acccessor functions. */
+/* Set of libunwind callback accessor functions. */
static unw_accessors_t ia64_vms_unw_accessors;
static unw_accessors_t ia64_vms_unw_rse_accessors;
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index ec0c059..565acca 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -74,7 +74,7 @@ inferior_event_handler (enum inferior_event_type event_type)
{
/* If the user was running a foreground execution
command, then propagate the error so that the prompt
- can be reenabled. Otherwise, the user already has
+ can be re-enabled. Otherwise, the user already has
the prompt and is typing some unrelated command, so
just inform the user and swallow the exception. */
if (current_ui->prompt_state == PROMPT_BLOCKED)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 6399278..af3ad0a 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -1276,7 +1276,7 @@ call_function_by_hand_dummy (struct value *function,
/* A call dummy always consists of just a single breakpoint, so
its address is the same as the address of the dummy.
- The actual breakpoint is inserted separatly so there is no need to
+ The actual breakpoint is inserted separately so there is no need to
write that out. */
bp_addr = dummy_addr;
break;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9f5b3d4..e03942d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -9444,7 +9444,7 @@ struct stop_context
ptid_t ptid;
- /* If stopp for a thread event, this is the thread that caused the
+ /* If stopped for a thread event, this is the thread that caused the
stop. */
thread_info_ref thread;
diff --git a/gdb/iq2000-tdep.c b/gdb/iq2000-tdep.c
index 094f627..6ec37fc 100644
--- a/gdb/iq2000-tdep.c
+++ b/gdb/iq2000-tdep.c
@@ -348,7 +348,7 @@ iq2000_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
/* Found a line number, use it as end of prologue. */
return sal.end;
- /* No useable line symbol. Use prologue parsing method. */
+ /* No usable line symbol. Use prologue parsing method. */
iq2000_init_frame_cache (&cache);
return iq2000_scan_prologue (gdbarch, func_addr, func_end, NULL, &cache);
}
diff --git a/gdb/language.c b/gdb/language.c
index a8548a2..4208c23 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -677,14 +677,6 @@ language_defn::is_string_type_p (struct type *type) const
return c_is_string_type_p (type);
}
-/* See language.h. */
-
-std::unique_ptr<compile_instance>
-language_defn::get_compile_instance () const
-{
- return {};
-}
-
/* The default implementation of the get_symbol_name_matcher_inner method
from the language_defn class. Matches with strncmp_iw. */
diff --git a/gdb/language.h b/gdb/language.h
index e6bfa3c..5e9599d 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -36,7 +36,6 @@ struct value_print_options;
struct type_print_options;
struct lang_varobj_ops;
struct parser_state;
-class compile_instance;
struct completion_match_for_lcd;
class innermost_block_tracker;
@@ -390,37 +389,6 @@ struct language_defn
symbol_name_matcher_ftype *get_symbol_name_matcher
(const lookup_name_info &lookup_name) const;
- /* If this language allows compilation from the gdb command line,
- then this method will return an instance of struct gcc_context
- appropriate to the language. If compilation for this language is
- generally supported, but something goes wrong then an exception
- is thrown. If compilation is not supported for this language
- then this method returns NULL. */
-
- virtual std::unique_ptr<compile_instance> get_compile_instance () const;
-
- /* This method must be overridden if 'get_compile_instance' is
- overridden.
-
- This takes the user-supplied text and returns a new bit of code
- to compile.
-
- INST is the compiler instance being used.
- INPUT is the user's input text.
- GDBARCH is the architecture to use.
- EXPR_BLOCK is the block in which the expression is being
- parsed.
- EXPR_PC is the PC at which the expression is being parsed. */
-
- virtual std::string compute_program (compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc) const
- {
- gdb_assert_not_reached ("language_defn::compute_program");
- }
-
/* Hash the given symbol search name. */
virtual unsigned int search_name_hash (const char *name) const;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 1727a06..e58fd66 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -133,7 +133,7 @@ process things as in sync mode, except that the we never block in
sigsuspend.
While processing an event, we may end up momentarily blocked in
-waitpid calls. Those waitpid calls, while blocking, are guarantied to
+waitpid calls. Those waitpid calls, while blocking, are guaranteed to
return quickly. E.g., in all-stop mode, before reporting to the core
that an LWP hit a breakpoint, all LWPs are stopped by sending them
SIGSTOP, and synchronously waiting for the SIGSTOP to be reported.
@@ -702,7 +702,7 @@ lwp_lwpid_htab_add_lwp (struct lwp_info *lp)
/* Head of doubly-linked list of known LWPs. Sorted by reverse
creation order. This order is assumed in some cases. E.g.,
- reaping status after killing alls lwps of a process: the leader LWP
+ reaping status after killing all lwps of a process: the leader LWP
must be reaped last. */
static intrusive_list<lwp_info> lwp_list;
diff --git a/gdb/linux-record.c b/gdb/linux-record.c
index 0b2709b..2f66337 100644
--- a/gdb/linux-record.c
+++ b/gdb/linux-record.c
@@ -609,7 +609,7 @@ record_linux_system_call (enum gdb_syscall syscall,
case gdb_sys_setgroups16:
break;
- case gdb_old_select:
+ case gdb_sys_old_select:
{
unsigned long sz_sel_arg = tdep->size_long + tdep->size_pointer * 4;
gdb_byte *a = (gdb_byte *) alloca (sz_sel_arg);
@@ -668,12 +668,12 @@ record_linux_system_call (enum gdb_syscall syscall,
return 1;
break;
- case gdb_old_readdir:
+ case gdb_sys_old_readdir:
if (record_mem_at_reg (regcache, tdep->arg2, tdep->size_old_dirent))
return -1;
break;
- case gdb_old_mmap:
+ case gdb_sys_old_mmap:
break;
case gdb_sys_munmap:
diff --git a/gdb/linux-record.h b/gdb/linux-record.h
index 6d6ba07..6656106 100644
--- a/gdb/linux-record.h
+++ b/gdb/linux-record.h
@@ -266,15 +266,15 @@ enum gdb_syscall {
gdb_sys_settimeofday = 79,
gdb_sys_getgroups16 = 80,
gdb_sys_setgroups16 = 81,
- gdb_old_select = 82,
+ gdb_sys_old_select = 82,
gdb_sys_symlink = 83,
gdb_sys_lstat = 84,
gdb_sys_readlink = 85,
gdb_sys_uselib = 86,
gdb_sys_swapon = 87,
gdb_sys_reboot = 88,
- gdb_old_readdir = 89,
- gdb_old_mmap = 90,
+ gdb_sys_old_readdir = 89,
+ gdb_sys_old_mmap = 90,
gdb_sys_munmap = 91,
gdb_sys_truncate = 92,
gdb_sys_ftruncate = 93,
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index fec6a63..852fea7 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1073,7 +1073,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
gdb_printf (_("Ignored signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
- gdb_printf (_("Catched signals bitmap: %s\n"),
+ gdb_printf (_("Caught signals bitmap: %s\n"),
hex_string (strtoulst (p, &p, 10)));
if (*p)
gdb_printf (_("wchan (system call): %s\n"),
@@ -2749,7 +2749,7 @@ linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
in the output, which requires scanning every thread in the thread
group to check whether a VMA is actually a thread's stack. With
Linux 4.4 on an Intel i7-4810MQ @ 2.80GHz, with an inferior with
- a few thousand threads, (1) takes a few miliseconds, while (2)
+ a few thousand threads, (1) takes a few milliseconds, while (2)
takes several seconds. Also note that "smaps", what we read for
determining core dump mappings, is even slower than "maps". */
xsnprintf (filename, sizeof filename, "/proc/%ld/task/%ld/maps", pid, pid);
diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c
index bd42d09..14d1887 100644
--- a/gdb/loongarch-linux-tdep.c
+++ b/gdb/loongarch-linux-tdep.c
@@ -812,7 +812,7 @@ loongarch_canonicalize_syscall (enum loongarch_syscall syscall_number)
SYSCALL_MAP (clone);
SYSCALL_MAP (execve);
- SYSCALL_MAP_RENAME (mmap, gdb_sys_mmap2);
+ SYSCALL_MAP_RENAME (mmap, gdb_sys_old_mmap);
SYSCALL_MAP (fadvise64);
SYSCALL_MAP (swapon);
@@ -938,7 +938,7 @@ loongarch_record_all_but_pc_registers (struct regcache *regcache)
return 0;
}
-/* Handler for LoongArch architechture system call instruction recording. */
+/* Handler for LoongArch architecture system call instruction recording. */
static int
loongarch_linux_syscall_record (struct regcache *regcache,
diff --git a/gdb/machoread.c b/gdb/machoread.c
index ac764c0..a9b1bea 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -164,7 +164,7 @@ macho_symtab_read (minimal_symbol_reader &reader,
S_NO_SO,
/* First SO read. Introduce an SO section, and may be followed by a second
- SO. The SO section should contain onl debugging symbols. */
+ SO. The SO section should contain only debugging symbols. */
S_FIRST_SO,
/* Second non-null SO found, just after the first one. Means that the first
diff --git a/gdb/main.c b/gdb/main.c
index b173eb6..ca34bf1 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -1124,7 +1124,7 @@ captured_main_1 (struct captured_main_args *context)
/* Do these (and anything which might call wrap_here or *_filtered)
after initialize_all_files() but before the interpreter has been
- installed. Otherwize the help/version messages will be eaten by
+ installed. Otherwise the help/version messages will be eaten by
the interpreter's output handler. */
if (print_version)
diff --git a/gdb/maint-test-options.c b/gdb/maint-test-options.c
index 9d76817..da9765e 100644
--- a/gdb/maint-test-options.c
+++ b/gdb/maint-test-options.c
@@ -137,6 +137,7 @@ struct test_options_opts
int pint_unl_opt = 0;
std::string string_opt;
std::string filename_opt;
+ ui_file_style::color color_opt { ui_file_style::MAGENTA };
test_options_opts () = default;
@@ -149,7 +150,7 @@ struct test_options_opts
gdb_printf (file,
_("-flag %d -xx1 %d -xx2 %d -bool %d "
"-enum %s -uint-unl %s -pint-unl %s -string '%s' "
- "-filename '%s' -- %s\n"),
+ "-filename '%s' -color %s -- %s\n"),
flag_opt,
xx1_opt,
xx2_opt,
@@ -163,6 +164,7 @@ struct test_options_opts
: plongest (pint_unl_opt)),
string_opt.c_str (),
filename_opt.c_str (),
+ color_opt.to_string ().c_str (),
args);
}
};
@@ -245,6 +247,14 @@ static const gdb::option::option_def test_options_option_defs[] = {
nullptr, /* show_cmd_cb */
N_("A filename option."),
},
+
+ /* A color option. */
+ gdb::option::color_option_def<test_options_opts> {
+ "color",
+ [] (test_options_opts *opts) { return &opts->color_opt; },
+ nullptr, /* show_cmd_cb */
+ N_("A color option."),
+ },
};
/* Create an option_def_group for the test_options_opts options, with
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index d5a0740..cdfac15 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -1119,7 +1119,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend,
case_stBlock_code:
found_ecoff_debugging_info = 1;
- /* Beginnning of (code) block. Value of symbol
+ /* Beginning of (code) block. Value of symbol
is the displacement from procedure start. */
push_parse_stack ();
@@ -2122,7 +2122,7 @@ parse_external (EXTR *es, int bigend, const section_offsets &section_offsets,
/* There is no need to parse the external procedure symbols.
If they are from objects compiled without -g, their index will
be indexNil, and the symbol definition from the minimal symbol
- is preferrable (yielding a function returning int instead of int).
+ is preferable (yielding a function returning int instead of int).
If the index points to a local procedure symbol, the local
symbol already provides the correct type.
Note that the index of the external procedure symbol points
@@ -2488,7 +2488,7 @@ parse_partial_symbols (minimal_symbol_reader &reader,
switch (ext_in->asym.st)
{
case stProc:
- /* Beginnning of Procedure */
+ /* Beginning of Procedure */
break;
case stStaticProc:
/* Load time only static procs */
@@ -2938,7 +2938,7 @@ parse_partial_symbols (minimal_symbol_reader &reader,
name SOs. */
/* Some other compilers (C++ ones in particular) emit
- useless SOs for non-existant .c files. We ignore
+ useless SOs for non-existent .c files. We ignore
all subsequent SOs that immediately follow the
first. */
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 3613f9b..331ef70 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -7027,7 +7027,7 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
/* FIXME: cagney/2003-06-26: Is this even necessary? The
disassembler needs to be able to locally determine the ISA, and
- not rely on GDB. Otherwize the stand-alone 'objdump -d' will not
+ not rely on GDB. Otherwise the stand-alone 'objdump -d' will not
work. */
if (mips_pc_is_mips16 (gdbarch, memaddr))
info->mach = bfd_mach_mips16;
diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c
index f69810f..ad73be2 100644
--- a/gdb/moxie-tdep.c
+++ b/gdb/moxie-tdep.c
@@ -240,7 +240,7 @@ moxie_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
return sal.end;
}
}
- /* No useable line symbol. Use result of prologue parsing
+ /* No usable line symbol. Use result of prologue parsing
method. */
return plg_end;
}
diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
index e08ead2..ed4e460 100644
--- a/gdb/nds32-tdep.c
+++ b/gdb/nds32-tdep.c
@@ -1935,7 +1935,7 @@ nds32_validate_tdesc_p (const struct target_desc *tdesc,
}
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called e.g. at program startup, when reading a core file, and when
diff --git a/gdb/observable.h b/gdb/observable.h
index deea1ff..c50891e 100644
--- a/gdb/observable.h
+++ b/gdb/observable.h
@@ -102,10 +102,14 @@ extern observable<inferior */* parent_inf */, inferior */* child_inf */,
extern observable<solib &/* solib */> solib_loaded;
/* The shared library SOLIB has been unloaded from program space PSPACE.
+ The SILENT argument indicates that GDB doesn't wish to notify the CLI
+ about any non-error consequences of unloading the solib, e.g. when
+ breakpoints are disabled.
+
Note when gdb calls this observer, the library's symbols have not
been unloaded yet, and thus are still available. */
extern observable<program_space *, const solib &/* solib */,
- bool /* still_in_use */> solib_unloaded;
+ bool /* still_in_use */, bool /* silent */> solib_unloaded;
/* The symbol file specified by OBJFILE has been loaded. */
extern observable<struct objfile */* objfile */> new_objfile;
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index 938d3cf..1128f24 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -765,7 +765,7 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */
= lookup_struct (copy_name ($2).c_str (),
pstate->expression_context_block);
}
- /* "const" and "volatile" are curently ignored. A type qualifier
+ /* "const" and "volatile" are currently ignored. A type qualifier
after the type is handled in the ptype rule. I think these could
be too. */
;
diff --git a/gdb/python/lib/gdb/dap/__init__.py b/gdb/python/lib/gdb/dap/__init__.py
index 145aeb6..08ca33f 100644
--- a/gdb/python/lib/gdb/dap/__init__.py
+++ b/gdb/python/lib/gdb/dap/__init__.py
@@ -26,6 +26,7 @@ from . import startup
# server object. "F401" is the flake8 "imported but unused" code.
from . import breakpoint # noqa: F401
from . import bt # noqa: F401
+from . import completions # noqa: F401
from . import disassemble # noqa: F401
from . import evaluate # noqa: F401
from . import launch # noqa: F401
diff --git a/gdb/python/lib/gdb/dap/completions.py b/gdb/python/lib/gdb/dap/completions.py
new file mode 100644
index 0000000..85acc43
--- /dev/null
+++ b/gdb/python/lib/gdb/dap/completions.py
@@ -0,0 +1,60 @@
+# 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/>.
+
+from typing import Optional
+
+from .frames import select_frame
+from .server import capability, import_column, import_line, request
+from .startup import exec_mi_and_log
+
+
+@request("completions")
+@capability("supportsCompletionsRequest")
+@capability("completionTriggerCharacters", [" ", "."])
+def completions(
+ *,
+ frameId: Optional[int] = None,
+ text: str,
+ column: int,
+ line: Optional[int] = None,
+ **extra,
+):
+ if frameId is not None:
+ select_frame(frameId)
+
+ column = import_column(column)
+ if line is None:
+ line = 1
+ else:
+ line = import_line(line)
+ text = text.splitlines()[line - 1]
+ text = text[: column - 1]
+ mi_result = exec_mi_and_log("-complete", text)
+ result = []
+ completion = None
+ if "completion" in mi_result:
+ completion = mi_result["completion"]
+ result.append({"label": completion, "length": len(completion)})
+ # If `-complete' finds one match then `completion' and `matches'
+ # will contain the same one match.
+ if (
+ completion is not None
+ and len(mi_result["matches"]) == 1
+ and completion == mi_result["matches"][0]
+ ):
+ return {"targets": result}
+ for match in mi_result["matches"]:
+ result.append({"label": match, "length": len(match)})
+ return {"targets": result}
diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py
index 8fdf029..7139c79 100644
--- a/gdb/python/lib/gdb/dap/server.py
+++ b/gdb/python/lib/gdb/dap/server.py
@@ -49,6 +49,7 @@ _server = None
# This is set by the initialize request and is used when rewriting
# line numbers.
_lines_start_at_1 = False
+_columns_start_at_1 = False
class DeferredRequest:
@@ -593,6 +594,8 @@ def initialize(**args):
_server.send_event_later("initialized")
global _lines_start_at_1
_lines_start_at_1 = client_bool_capability("linesStartAt1", True)
+ global _columns_start_at_1
+ _columns_start_at_1 = client_bool_capability("columnsStartAt1", True)
return _capabilities.copy()
@@ -698,7 +701,7 @@ def send_gdb_with_response(fn):
return val
-def export_line(line):
+def export_line(line: int) -> int:
"""Rewrite LINE according to client capability.
This applies the linesStartAt1 capability as needed,
when sending a line number from gdb to the client."""
@@ -710,7 +713,7 @@ def export_line(line):
return line
-def import_line(line):
+def import_line(line: int) -> int:
"""Rewrite LINE according to client capability.
This applies the linesStartAt1 capability as needed,
when the client sends a line number to gdb."""
@@ -720,3 +723,17 @@ def import_line(line):
# the client starts at 0.
line = line + 1
return line
+
+
+def export_column(column: int) -> int:
+ """Rewrite COLUMN according to client capability.
+ This applies the columnsStartAt1 capability as needed,
+ when sending a column number from gdb to the client."""
+ return column if _columns_start_at_1 else column - 1
+
+
+def import_column(column: int) -> int:
+ """Rewrite COLUMN according to client capability.
+ This applies the columnsStartAt1 capability as needed,
+ when the client sends a column number to gdb."""
+ return column if _columns_start_at_1 else column + 1
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 6d05651..09f0e94 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1647,7 +1647,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno)
/* "xfer_partial" method. Behavior is conditional on
RECORD_FULL_IS_REPLAY.
- In replay mode, we cannot write memory unles we are willing to
+ In replay mode, we cannot write memory unless we are willing to
invalidate the record/replay log from this point forward. */
enum target_xfer_status
@@ -2368,7 +2368,7 @@ record_full_restore (void)
bfdcore_read (current_program_space->core_bfd (), osec, &magic,
sizeof (magic), &bfd_offset);
if (magic != RECORD_FULL_FILE_MAGIC)
- error (_("Version mis-match or file format error in core file %s."),
+ error (_("Version mismatch or file format error in core file %s."),
bfd_get_filename (current_program_space->core_bfd ()));
if (record_debug)
gdb_printf (gdb_stdlog,
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 5508778..ad72429 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1911,32 +1911,13 @@ public:
{}
};
-/* Return true if regcache::cooked_{read,write}_test should be skipped for
- GDBARCH. */
-
-static bool
-selftest_skiparch (struct gdbarch *gdbarch)
-{
- const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name;
-
- /* Avoid warning:
- Running selftest regcache::cooked_{read,write}_test::m68hc11.
- warning: No frame soft register found in the symbol table.
- Stack backtrace will not work.
- We could instead capture the output and then filter out the warning, but
- that seems more trouble than it's worth. */
- return (strcmp (name, "m68hc11") == 0
- || strcmp (name, "m68hc12") == 0
- || strcmp (name, "m68hc12:HCS12") == 0);
-}
-
/* Test regcache::cooked_read gets registers from raw registers and
memory instead of target to_{fetch,store}_registers. */
static void
cooked_read_test (struct gdbarch *gdbarch)
{
- if (selftest_skiparch (gdbarch))
+ if (selftest_skip_warning_arch (gdbarch))
return;
scoped_mock_context<target_ops_no_register> mockctx (gdbarch);
@@ -2074,7 +2055,7 @@ cooked_read_test (struct gdbarch *gdbarch)
static void
cooked_write_test (struct gdbarch *gdbarch)
{
- if (selftest_skiparch (gdbarch))
+ if (selftest_skip_warning_arch (gdbarch))
return;
/* Create a mock environment. A process_stratum target pushed. */
diff --git a/gdb/remote.c b/gdb/remote.c
index 66c58c8..8456750 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9035,7 +9035,7 @@ remote_target::process_g_packet (struct regcache *regcache)
/* Reply describes registers byte by byte, each byte encoded as two
hex characters. Suck them all up, then supply them to the
- register cacheing/storage mechanism. */
+ register caching/storage mechanism. */
p = rs->buf.data ();
for (i = 0; i < rsa->sizeof_g_packet; i++)
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 6eeb1c1..4c18f14 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -4188,7 +4188,7 @@ static const char *const stap_register_indirection_suffixes[] =
};
/* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
+ reuse an architecture from ARCHES, which is a list of
architectures already created during this debugging session.
Called e.g. at program startup, when reading a core file, and when
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 0d1c89b..5fdabeb 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -6951,7 +6951,7 @@ ppc_process_record_prefix_store_vsx_ds_form (struct gdbarch *gdbarch,
}
/* Record the prefixed VSX, form D, instructions. The arguments are the
- instruction address for PC-relative addresss (addr), the first 32-bits of
+ instruction address for PC-relative address (addr), the first 32-bits of
the instruction (insn_prefix) and the following 32-bits of the instruction
(insn_suffix). Return 0 on success. */
@@ -7583,7 +7583,7 @@ ppc64_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
return pc + 4;
}
-/* Initialize the current architecture based on INFO. If possible, re-use an
+/* Initialize the current architecture based on INFO. If possible, reuse an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
diff --git a/gdb/run-on-main-thread.c b/gdb/run-on-main-thread.c
index 746ea35..50efe07 100644
--- a/gdb/run-on-main-thread.c
+++ b/gdb/run-on-main-thread.c
@@ -83,7 +83,7 @@ run_events (int error, gdb_client_data client_data)
}
catch (const gdb_exception_quit &e)
{
- /* Should cancelation of a runnable event cancel the execution of
+ /* Should cancellation of a runnable event cancel the execution of
the following one? The answer is not clear, so keep doing what
we've done so far: ignore this exception. */
}
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 8bec934..adcec63 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -116,7 +116,8 @@ rust_tuple_type_p (struct type *type)
}
/* Return true if all non-static fields of a structlike type are in a
- sequence like __0, __1, __2. */
+ sequence like 0, 1, 2. "__" prefixes are also accepted -- rustc
+ emits "__0" but gccrs emits "0". */
static bool
rust_underscore_fields (struct type *type)
@@ -131,8 +132,12 @@ rust_underscore_fields (struct type *type)
{
char buf[20];
- xsnprintf (buf, sizeof (buf), "__%d", field_number);
- if (strcmp (buf, type->field (i).name ()) != 0)
+ xsnprintf (buf, sizeof (buf), "%d", field_number);
+
+ const char *field_name = type->field (i).name ();
+ if (startswith (field_name, "__"))
+ field_name += 2;
+ if (strcmp (buf, field_name) != 0)
return false;
field_number++;
}
@@ -1476,7 +1481,7 @@ rust_struct_anon::evaluate (struct type *expect_type,
value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
int field_number = std::get<0> (m_storage);
- struct type *type = lhs->type ();
+ struct type *type = check_typedef (lhs->type ());
if (type->code () == TYPE_CODE_STRUCT)
{
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 41faf93..bb204fe 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -2488,7 +2488,7 @@ s390_prologue_frame_unwind_cache (const frame_info_ptr &this_frame,
size zero. This is only possible if the next frame is a sentinel
frame, a dummy frame, or a signal trampoline frame. */
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be
- needed, instead the code should simpliy rely on its
+ needed, instead the code should simply rely on its
analysis. */
next_frame = get_next_frame (this_frame);
while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
@@ -2537,7 +2537,7 @@ s390_prologue_frame_unwind_cache (const frame_info_ptr &this_frame,
code at a point where the frame pointer has already been restored.
This can only happen in an innermost frame. */
/* FIXME: cagney/2004-05-01: This sanity check shouldn't be needed,
- instead the code should simpliy rely on its analysis. */
+ instead the code should simply rely on its analysis. */
next_frame = get_next_frame (this_frame);
while (next_frame && get_frame_type (next_frame) == INLINE_FRAME)
next_frame = get_next_frame (next_frame);
diff --git a/gdb/selftest-arch.c b/gdb/selftest-arch.c
index 17eeba8..79889c0 100644
--- a/gdb/selftest-arch.c
+++ b/gdb/selftest-arch.c
@@ -108,5 +108,24 @@ reset ()
registers_changed ();
reinit_frame_cache ();
}
+
+/* See selftest-arch.h. */
+
+bool
+selftest_skip_warning_arch (struct gdbarch *gdbarch)
+{
+ const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name;
+
+ /* Avoid warning:
+ Running selftest <test>::m68hc11.
+ warning: No frame soft register found in the symbol table.
+ Stack backtrace will not work.
+ We could instead capture the output and then filter out the warning, but
+ that seems more trouble than it's worth. */
+ return (strcmp (name, "m68hc11") == 0
+ || strcmp (name, "m68hc12") == 0
+ || strcmp (name, "m68hc12:HCS12") == 0);
+}
+
} /* namespace selftests */
#endif /* GDB_SELF_TEST */
diff --git a/gdb/selftest-arch.h b/gdb/selftest-arch.h
index db11723..c6a85fa 100644
--- a/gdb/selftest-arch.h
+++ b/gdb/selftest-arch.h
@@ -29,6 +29,11 @@ namespace selftests
extern void
register_test_foreach_arch (const std::string &name,
self_test_foreach_arch_function *function);
+
+/* Return true if GDBARCH should be skipped in some selftests to avoid
+ warnings. */
+
+extern bool selftest_skip_warning_arch (struct gdbarch *gdbarch);
}
#endif /* GDB_SELFTEST_ARCH_H */
diff --git a/gdb/ser-mingw.c b/gdb/ser-mingw.c
index 2603bb8..a1a59ee 100644
--- a/gdb/ser-mingw.c
+++ b/gdb/ser-mingw.c
@@ -281,10 +281,10 @@ ser_windows_wait_handle (struct serial *scb, HANDLE *read, HANDLE *except)
cleared, and we get a duplicated event, if the last batch
of characters included at least two arriving close together. */
if (!SetCommMask (h, 0))
- warning (_("ser_windows_wait_handle: reseting mask failed"));
+ warning (_("ser_windows_wait_handle: resetting mask failed"));
if (!SetCommMask (h, EV_RXCHAR))
- warning (_("ser_windows_wait_handle: reseting mask failed (2)"));
+ warning (_("ser_windows_wait_handle: resetting mask failed (2)"));
/* There's a potential race condition here; we must check cbInQue
and not wait if that's nonzero. */
diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c
index 02845aa..1913309 100644
--- a/gdb/ser-unix.c
+++ b/gdb/ser-unix.c
@@ -404,7 +404,7 @@ rate_to_code (int rate)
for (i = 0; baudtab[i].rate != -1; i++)
{
- /* test for perfect macth. */
+ /* test for perfect match. */
if (rate == baudtab[i].rate)
return baudtab[i].code;
else
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index 6c7d906..cbd89b1 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -146,24 +146,13 @@ struct lm_info_darwin final : public lm_info
static CORE_ADDR
lookup_symbol_from_bfd (bfd *abfd, const char *symname)
{
- long storage_needed;
- asymbol **symbol_table;
- unsigned int number_of_symbols;
- unsigned int i;
CORE_ADDR symaddr = 0;
- storage_needed = bfd_get_symtab_upper_bound (abfd);
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (abfd, false);
- if (storage_needed <= 0)
- return 0;
-
- symbol_table = (asymbol **) xmalloc (storage_needed);
- number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
-
- for (i = 0; i < number_of_symbols; i++)
+ for (const asymbol *sym : symbol_table)
{
- asymbol *sym = symbol_table[i];
-
if (strcmp (sym->name, symname) == 0
&& (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0)
{
@@ -172,7 +161,6 @@ lookup_symbol_from_bfd (bfd *abfd, const char *symname)
break;
}
}
- xfree (symbol_table);
return symaddr;
}
diff --git a/gdb/solib-rocm.c b/gdb/solib-rocm.c
index 156b36a..b49f529 100644
--- a/gdb/solib-rocm.c
+++ b/gdb/solib-rocm.c
@@ -403,7 +403,7 @@ protected:
/* Snapshot of the original ELF image taken during load. This is done to
support the situation where an inferior uses an in-memory image, and
- releases or re-uses this memory before GDB is done using it. */
+ releases or reuses this memory before GDB is done using it. */
gdb::byte_vector m_objfile_image;
LONGEST size () override
diff --git a/gdb/solib.c b/gdb/solib.c
index 7782c8d..1d26970 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -68,7 +68,7 @@ show_solib_search_path (struct ui_file *file, int from_tty,
value);
}
-/* Same as HAVE_DOS_BASED_FILE_SYSTEM, but useable as an rvalue. */
+/* Same as HAVE_DOS_BASED_FILE_SYSTEM, but usable as an rvalue. */
#if (HAVE_DOS_BASED_FILE_SYSTEM)
#define DOS_BASED_FILE_SYSTEM 1
#else
@@ -694,14 +694,17 @@ notify_solib_loaded (solib &so)
/* Notify interpreters and observers that solib SO has been unloaded.
When STILL_IN_USE is true, the objfile backing SO is still in use,
this indicates that SO was loaded multiple times, but only mapped
- in once (the mapping was reused). */
+ in once (the mapping was reused).
+
+ When SILENT is true, don't announce to the user if any breakpoints are
+ disabled as a result of unloading SO. */
static void
notify_solib_unloaded (program_space *pspace, const solib &so,
- bool still_in_use)
+ bool still_in_use, bool silent)
{
interps_notify_solib_unloaded (so, still_in_use);
- gdb::observers::solib_unloaded.notify (pspace, so, still_in_use);
+ gdb::observers::solib_unloaded.notify (pspace, so, still_in_use, silent);
}
/* See solib.h. */
@@ -803,7 +806,7 @@ update_solib_list (int from_tty)
/* Notify any observer that the shared object has been
unloaded before we remove it from GDB's tables. */
notify_solib_unloaded (current_program_space, *gdb_iter,
- still_in_use);
+ still_in_use, false);
/* Unless the user loaded it explicitly, free SO's objfile. */
if (gdb_iter->objfile != nullptr
@@ -1163,14 +1166,12 @@ clear_solib (program_space *pspace)
{
const solib_ops *ops = gdbarch_so_ops (current_inferior ()->arch ());
- disable_breakpoints_in_shlibs (pspace);
-
for (solib &so : pspace->so_list)
{
bool still_in_use
= (so.objfile != nullptr && solib_used (pspace, so));
- notify_solib_unloaded (pspace, so, still_in_use);
+ notify_solib_unloaded (pspace, so, still_in_use, true);
pspace->remove_target_sections (&so);
};
@@ -1431,49 +1432,38 @@ CORE_ADDR
gdb_bfd_lookup_symbol_from_symtab (
bfd *abfd, gdb::function_view<bool (const asymbol *)> match_sym)
{
- long storage_needed = bfd_get_symtab_upper_bound (abfd);
CORE_ADDR symaddr = 0;
+ gdb::array_view<asymbol *> symbol_table
+ = gdb_bfd_canonicalize_symtab (abfd, false);
- if (storage_needed > 0)
+ for (asymbol *sym : symbol_table)
{
- unsigned int i;
-
- gdb::def_vector<asymbol *> storage (storage_needed / sizeof (asymbol *));
- asymbol **symbol_table = storage.data ();
- unsigned int number_of_symbols
- = bfd_canonicalize_symtab (abfd, symbol_table);
-
- for (i = 0; i < number_of_symbols; i++)
+ if (match_sym (sym))
{
- asymbol *sym = *symbol_table++;
-
- if (match_sym (sym))
+ gdbarch *gdbarch = current_inferior ()->arch ();
+ symaddr = sym->value;
+
+ /* Some ELF targets fiddle with addresses of symbols they
+ consider special. They use minimal symbols to do that
+ and this is needed for correct breakpoint placement,
+ but we do not have full data here to build a complete
+ minimal symbol, so just set the address and let the
+ targets cope with that. */
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && gdbarch_elf_make_msymbol_special_p (gdbarch))
{
- gdbarch *gdbarch = current_inferior ()->arch ();
- symaddr = sym->value;
-
- /* Some ELF targets fiddle with addresses of symbols they
- consider special. They use minimal symbols to do that
- and this is needed for correct breakpoint placement,
- but we do not have full data here to build a complete
- minimal symbol, so just set the address and let the
- targets cope with that. */
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
- && gdbarch_elf_make_msymbol_special_p (gdbarch))
+ struct minimal_symbol msym
{
- struct minimal_symbol msym
- {
- };
+ };
- msym.set_value_address (symaddr);
- gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym);
- symaddr = CORE_ADDR (msym.unrelocated_address ());
- }
-
- /* BFD symbols are section relative. */
- symaddr += sym->section->vma;
- break;
+ msym.set_value_address (symaddr);
+ gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym);
+ symaddr = CORE_ADDR (msym.unrelocated_address ());
}
+
+ /* BFD symbols are section relative. */
+ symaddr += sym->section->vma;
+ break;
}
}
diff --git a/gdb/sparc-obsd-tdep.c b/gdb/sparc-obsd-tdep.c
index 2bc944e..8329f3a 100644
--- a/gdb/sparc-obsd-tdep.c
+++ b/gdb/sparc-obsd-tdep.c
@@ -147,7 +147,7 @@ static const struct frame_unwind_legacy sparc32obsd_sigtramp_frame_unwind (
-/* Offset wthin the thread structure where we can find %fp and %i7. */
+/* Offset within the thread structure where we can find %fp and %i7. */
#define SPARC32OBSD_UTHREAD_FP_OFFSET 128
#define SPARC32OBSD_UTHREAD_PC_OFFSET 132
diff --git a/gdb/sparc-sol2-nat.c b/gdb/sparc-sol2-nat.c
index 8f9607f..8d04696 100644
--- a/gdb/sparc-sol2-nat.c
+++ b/gdb/sparc-sol2-nat.c
@@ -26,7 +26,7 @@
#include "target.h"
#include "procfs.h"
-/* This file provids the (temporary) glue between the Solaris SPARC
+/* This file provides the (temporary) glue between the Solaris SPARC
target dependent code and the machine independent SVR4 /proc
support. */
diff --git a/gdb/sparc64-obsd-tdep.c b/gdb/sparc64-obsd-tdep.c
index 8596d2f..175ccb5 100644
--- a/gdb/sparc64-obsd-tdep.c
+++ b/gdb/sparc64-obsd-tdep.c
@@ -318,7 +318,7 @@ static const struct frame_unwind_legacy sparc64obsd_trapframe_unwind (
/* Threads support. */
-/* Offset wthin the thread structure where we can find %fp and %i7. */
+/* Offset within the thread structure where we can find %fp and %i7. */
#define SPARC64OBSD_UTHREAD_FP_OFFSET 232
#define SPARC64OBSD_UTHREAD_PC_OFFSET 240
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index fcc226e..73f50fe 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -891,7 +891,7 @@ read_ofile_symtab (struct objfile *objfile, legacy_psymtab *pst)
symnum < max_symnum;
symnum++)
{
- QUIT; /* Allow this to be interruptable. */
+ QUIT; /* Allow this to be interruptible. */
if (symbuf_idx == symbuf_end)
fill_symbuf (abfd, objfile);
bufp = &symbuf[symbuf_idx++];
@@ -1301,7 +1301,7 @@ read_stabs_symtab_1 (minimal_symbol_reader &reader,
for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++)
{
/* Get the symbol for this run and pull out some info. */
- QUIT; /* Allow this to be interruptable. */
+ QUIT; /* Allow this to be interruptible. */
if (symbuf_idx == symbuf_end)
fill_symbuf (abfd, objfile);
bufp = &symbuf[symbuf_idx++];
@@ -1540,7 +1540,7 @@ read_stabs_symtab_1 (minimal_symbol_reader &reader,
}
/* Some other compilers (C++ ones in particular) emit useless
- SOs for non-existant .c files. We ignore all subsequent SOs
+ SOs for non-existent .c files. We ignore all subsequent SOs
that immediately follow the first. */
if (!pst)
@@ -3511,7 +3511,7 @@ define_symbol (CORE_ADDR valu, const char *string, int desc, int type,
sym->set_aclass_index (LOC_STATIC);
sym->set_domain (VAR_DOMAIN);
/* Don't add symbol references to global_sym_chain.
- Symbol references don't have valid names and wont't match up with
+ Symbol references don't have valid names and won't match up with
minimal symbols when the global_sym_chain is relocated.
We'll fixup symbol references when we fixup the defining symbol. */
if (sym->linkage_name () && sym->linkage_name ()[0] != '#')
@@ -4907,7 +4907,7 @@ read_member_functions (struct stab_field_info *fip, const char **pp,
int nbits;
/* virtual member function, followed by index.
The sign bit is set to distinguish pointers-to-methods
- from virtual function indicies. Since the array is
+ from virtual function indices. Since the array is
in words, the quantity must be shifted left by 1
on 16 bit machine, and by 2 on 32 bit machine, forcing
the sign bit out, and usable as a valid index into
diff --git a/gdb/stabsread.h b/gdb/stabsread.h
index 273ceaa..99ca215 100644
--- a/gdb/stabsread.h
+++ b/gdb/stabsread.h
@@ -131,7 +131,7 @@ struct header_file
/* The actual length of HEADER_FILES. */
#define N_HEADER_FILES(OBJFILE) (DBX_SYMFILE_INFO (OBJFILE)->n_header_files)
-/* The allocated lengh of HEADER_FILES. */
+/* The allocated length of HEADER_FILES. */
#define N_ALLOCATED_HEADER_FILES(OBJFILE) \
(DBX_SYMFILE_INFO (OBJFILE)->n_allocated_header_files)
diff --git a/gdb/stack.c b/gdb/stack.c
index 6f986aa..6c4e0cd 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -827,7 +827,7 @@ print_frame_args (const frame_print_options &fp_opts,
(1) Because find_saved_registers may be slow for
remote debugging.
- (2) Because registers are often re-used and stack
+ (2) Because registers are often reused and stack
slots rarely (never?) are. Therefore using
the stack slot is much less likely to print
garbage.
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index b312b38..fc37a59 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1225,7 +1225,7 @@ stap_parse_argument (const char **arg, struct type *atype,
{
/* We need to initialize the expression buffer, in order to begin
our parsing efforts. We use language_c here because we may need
- to do pointer arithmetics. */
+ to do pointer arithmetic. */
struct stap_parse_info p (*arg, atype, language_def (language_c),
gdbarch);
diff --git a/gdb/symfile.c b/gdb/symfile.c
index b0c178a..6c3af61 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -3035,7 +3035,7 @@ section_is_mapped (struct obj_section *osect)
case ovly_off:
return 0; /* overlay debugging off */
case ovly_auto: /* overlay debugging automatic */
- /* Unles there is a gdbarch_overlay_update function,
+ /* Unless there is a gdbarch_overlay_update function,
there's really nothing useful to do here (can't really go auto). */
gdbarch = osect->objfile->arch ();
if (gdbarch_overlay_update_p (gdbarch))
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 06e2cd5..3ab1a58 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -6550,7 +6550,7 @@ find_main_name (void)
language. It is easy to guaranty this with Ada, since we use a
special symbol generated only when the main in Ada to find the name
of the main procedure. It is difficult however to see how this can
- be guarantied for languages such as C, for instance. This suggests
+ be guaranteed for languages such as C, for instance. This suggests
that order of call for these methods becomes important, which means
a more complicated approach. */
new_main_name = ada_main_name ();
diff --git a/gdb/testsuite/gdb.ada/array_of_variant.exp b/gdb/testsuite/gdb.ada/array_of_variant.exp
index 8b83f4e..83b626c 100644
--- a/gdb/testsuite/gdb.ada/array_of_variant.exp
+++ b/gdb/testsuite/gdb.ada/array_of_variant.exp
@@ -20,7 +20,7 @@ require allow_ada_tests
standard_ada_testfile p
-set old_gcc [gnat_version_compare <= 7]
+set old_gcc [gnat_version_compare < 8]
proc gdb_test_with_xfail { cmd re re_xfail msg } {
global scenario old_gcc
diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp
index 03ead59..a1dd974 100644
--- a/gdb/testsuite/gdb.base/filename-completion.exp
+++ b/gdb/testsuite/gdb.base/filename-completion.exp
@@ -381,11 +381,15 @@ proc run_mid_line_completion_tests { root cmd } {
proc run_quoting_and_escaping_tests { root } {
# Test all the commands which allow quoting of filenames, and
# which require whitespace to be escaped in unquoted filenames.
- foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file \
- remove-symbol-file \
- "target core" "target exec" "target tfile" \
- "maint print c-tdesc" "compile file" \
- "save gdb-index" "save gdb-index -dwarf-5" } {
+ set all_cmds { file exec-file symbol-file add-symbol-file \
+ remove-symbol-file \
+ "target core" "target exec" "target tfile" \
+ "maint print c-tdesc" "save gdb-index"
+ "save gdb-index -dwarf-5" }
+ if { [allow_compile_tests] } {
+ lappend all_cmds "compile file"
+ }
+ foreach_with_prefix cmd $all_cmds {
# Try each test placing the filename as the first argument
# then again with a quoted string immediately after the
# command. This works because the filename completer will
diff --git a/gdb/testsuite/gdb.base/gstack.exp b/gdb/testsuite/gdb.base/gstack.exp
index 8df36b1..89be676 100644
--- a/gdb/testsuite/gdb.base/gstack.exp
+++ b/gdb/testsuite/gdb.base/gstack.exp
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Free Software Foundation, Inc.
+# Copyright (C) 2024-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
@@ -62,8 +62,10 @@ if { ![gdb_assert { ![expr {$res < 0 || $res == ""}] } $test] } {
set test "got backtrace"
set saw_backtrace false
set no_awk false
+set location_re ${srcfile}:${decimal}
+
gdb_expect {
- -i "$res" -re "#0 +(0x\[0-9a-f\]+ in )?main \(\).*\r\nGSTACK-END\r\n\$" {
+ -i "$res" -re "#0 +(0x\[0-9a-f\]+ in )?main \(\).*$location_re.*\r\nGSTACK-END\r\n\$" {
set saw_backtrace true
pass $test
exp_continue
diff --git a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp
index 45086f6..46561a9 100644
--- a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp
+++ b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.exp
@@ -72,77 +72,89 @@ gdb_continue_to_breakpoint "stop at test breakpoint"
gdb_test_no_output "source ${pyfile}"\
"import python scripts"
-# Check the unbroken stack.
-gdb_test_sequence "bt" "backtrace when the unwind is left unbroken" {
- "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at "
- "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at "
- "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at "
- "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at "
- "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at "
- "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at "
- "\\r\\n#6 \[^\r\n\]* main \\(\\) at "
-}
+# Test with and without filters.
+foreach bt_cmd { "bt" "bt -no-filters" } {
+ with_test_prefix "$bt_cmd" {
-with_test_prefix "cycle at level 5" {
- # Arrange to introduce a stack cycle at frame 5.
- gdb_test_no_output "python stop_at_level=5"
- gdb_test "maint flush register-cache" \
- "Register cache flushed\\."
- gdb_test_lines "bt" "backtrace when the unwind is broken at frame 5" \
- [multi_line \
- "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
-}
+ # Check the unbroken stack.
+ gdb_test_sequence "$bt_cmd" "backtrace when the unwind is left unbroken" {
+ "\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at "
+ "\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at "
+ "\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at "
+ "\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at "
+ "\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at "
+ "\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at "
+ "\\r\\n#6 \[^\r\n\]* main \\(\\) at "
+ }
-with_test_prefix "cycle at level 3" {
- # Arrange to introduce a stack cycle at frame 3.
- gdb_test_no_output "python stop_at_level=3"
- gdb_test "maint flush register-cache" \
- "Register cache flushed\\."
- gdb_test_lines "bt" "backtrace when the unwind is broken at frame 3" \
- [multi_line \
- "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
-}
+ with_test_prefix "cycle at level 5" {
+ # Arrange to introduce a stack cycle at frame 5.
+ gdb_test_no_output "python stop_at_level=5"
+ gdb_test "maint flush register-cache" \
+ "Register cache flushed\\."
+ gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 5" \
+ [multi_line \
+ "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
+ }
-with_test_prefix "cycle at level 1" {
- # Arrange to introduce a stack cycle at frame 1.
- gdb_test_no_output "python stop_at_level=1"
- gdb_test "maint flush register-cache" \
- "Register cache flushed\\."
- gdb_test_lines "bt" "backtrace when the unwind is broken at frame 1" \
- [multi_line \
- "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
- "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
- "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
-}
+ with_test_prefix "cycle at level 3" {
+ # Arrange to introduce a stack cycle at frame 3.
+ gdb_test_no_output "python stop_at_level=3"
+ gdb_test "maint flush register-cache" \
+ "Register cache flushed\\."
+ gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 3" \
+ [multi_line \
+ "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
+ }
-# Flush the register cache (which also flushes the frame cache) so we
-# get a full backtrace again, then switch on frame debugging and try
-# to back trace. At one point this triggered an assertion.
-gdb_test "maint flush register-cache" \
- "Register cache flushed\\." ""
-gdb_test_no_output "set debug frame 1"
-set ok 1
-gdb_test_multiple "bt" "backtrace with debugging on" {
- -re "^$gdb_prompt $" {
- gdb_assert { $ok } $gdb_test_name
- }
- -re "Python Exception <class 'gdb.error'>: \[^\r\n\]*\r\n" {
- set ok 0
- exp_continue
- }
- -re "\[^\r\n\]+\r\n" {
- exp_continue
+ with_test_prefix "cycle at level 1" {
+ # Arrange to introduce a stack cycle at frame 1.
+ gdb_test_no_output "python stop_at_level=1"
+ gdb_test "maint flush register-cache" \
+ "Register cache flushed\\."
+ gdb_test_lines "$bt_cmd" "backtrace when the unwind is broken at frame 1" \
+ [multi_line \
+ "#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
+ "#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
+ "Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
+ }
+
+ # Flush the register cache (which also flushes the frame cache) so we
+ # get a full backtrace again, then switch on frame debugging and try
+ # to back trace. At one point this triggered an assertion.
+ gdb_test "maint flush register-cache" \
+ "Register cache flushed\\." ""
+ gdb_test_no_output "set debug frame 1"
+ set ok 1
+ gdb_test_multiple "$bt_cmd" "backtrace with debugging on" {
+ -re "^$gdb_prompt $" {
+ gdb_assert { $ok } $gdb_test_name
+ }
+ -re "Python Exception <class 'gdb.error'>: \[^\r\n\]*\r\n" {
+ set ok 0
+ exp_continue
+ }
+ -re "\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ }
+ gdb_test "p 1 + 2 + 3" " = 6" \
+ "ensure GDB is still alive"
+
+ # Prepare for the next iteration of the test loop
+ gdb_test_no_output "set debug frame 0"
+ gdb_test_no_output "python stop_at_level=None"
+ gdb_test "maint flush register-cache" \
+ "Register cache flushed\\." "maint flush register-cache at (loop end)"
}
}
-gdb_test "p 1 + 2 + 3" " = 6" \
- "ensure GDB is still alive"
diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp
index a1ca39e..8760a91 100644
--- a/gdb/testsuite/gdb.base/options.exp
+++ b/gdb/testsuite/gdb.base/options.exp
@@ -99,21 +99,21 @@ proc make_cmd {variant} {
# operand.
proc expect_none {operand} {
return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '' -filename '' -- $operand"
+ -string '' -filename '' -color magenta -- $operand"
}
# Return a string for the expected result of running "maint
# test-options xxx", with -flag set. OPERAND is the expected operand.
proc expect_flag {operand} {
return "-flag 1 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '' -filename '' -- $operand"
+ -string '' -filename '' -color magenta -- $operand"
}
# Return a string for the expected result of running "maint
# test-options xxx", with -bool set. OPERAND is the expected operand.
proc expect_bool {operand} {
return "-flag 0 -xx1 0 -xx2 0 -bool 1 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '' -filename '' -- $operand"
+ -string '' -filename '' -color magenta -- $operand"
}
# Return a string for the expected result of running "maint
@@ -123,10 +123,10 @@ proc expect_bool {operand} {
proc expect_integer {option val operand} {
if {$option == "uinteger-unlimited"} {
return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl $val\
- -pint-unl 0 -string '' -filename '' -- $operand"
+ -pint-unl 0 -string '' -filename '' -color magenta -- $operand"
} elseif {$option == "pinteger-unlimited"} {
return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0\
- -pint-unl $val -string '' -filename '' -- $operand"
+ -pint-unl $val -string '' -filename '' -color magenta -- $operand"
} else {
error "unsupported option: $option"
}
@@ -144,7 +144,7 @@ proc expect_string {str operand} {
set str [string range $str 1 end-1]
}
return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '$str' -filename '' -- $operand"
+ -string '$str' -filename '' -color magenta -- $operand"
}
# Return a string for the expected result of running "maint
@@ -159,11 +159,12 @@ proc expect_filename {str operand} {
set str [string range $str 1 end-1]
}
return "-flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '' -filename '$str' -- $operand"
+ -string '' -filename '$str' -color magenta -- $operand"
}
set all_options {
"-bool"
+ "-color"
"-enum"
"-filename"
"-flag"
@@ -628,7 +629,7 @@ proc_with_prefix test-flag {variant} {
# Extract twice the same flag, separated by one space.
gdb_test "$cmd -xx1 -xx2 -xx1 -xx2 -xx1 -- non flags args" \
"-flag 0 -xx1 1 -xx2 1 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0\
- -string '' -filename '' -- non flags args"
+ -string '' -filename '' -color magenta -- non flags args"
# Extract 2 known flags in front of unknown flags.
gdb_test "$cmd -xx1 -xx2 -a -b -c -xx1 --" \
diff --git a/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c
new file mode 100644
index 0000000..685a22e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2012-2025 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include <stdlib.h>
+
+/* Global var used to generate filler code. */
+volatile int global_var = 0;
+
+int
+main ()
+{
+ global_var++;
+ global_var++;
+
+ abort ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp
new file mode 100644
index 0000000..cf74789
--- /dev/null
+++ b/gdb/testsuite/gdb.base/set-solib-absolute-prefix.exp
@@ -0,0 +1,51 @@
+# Copyright 2012-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/>.
+#
+# Compile a 32-bit x86 executable and then stop within a system call.
+# Change the sysroot to a non-existent directory, GDB should try (and
+# fail) to reload the currently loaded shared libraries. However, GDB
+# should retain the symbols for the vDSO library as that is not loaded
+# from the file system.
+#
+# Check the backtrace to ensure that the __kernel_vsyscall symbol is
+# still in the backtrace, this indicates GDB still has the vDSO
+# symbols available.
+
+require {is_any_target "i?86-*-linux*" "x86_64-*-linux*"}
+standard_testfile
+
+# The binary must be compiled as 32-bit so that the system call
+# `__kernel_vsyscall' originates from vDSO.
+set flags { debug }
+if { ![is_ilp32_target] } {
+ lappend flags "additional_flags=-m32"
+}
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile $flags] } {
+ return
+}
+
+if { ![runto_main] } {
+ return
+}
+
+set non_existing_directory [standard_output_file "BOGUS"]
+
+gdb_test "continue" "Program received signal SIGABRT, Aborted.*" \
+ "continue until abort"
+gdb_test "set sysroot $non_existing_directory" \
+ ".*warning: Unable to find dynamic linker breakpoint function.*" \
+ "set sysroot"
+gdb_test "bt" "__kernel_vsyscall.*" "backtrace with __kernel_vsyscall"
diff --git a/gdb/testsuite/gdb.base/shlib-unload.exp b/gdb/testsuite/gdb.base/shlib-unload.exp
index f3e8cce..9d47416 100644
--- a/gdb/testsuite/gdb.base/shlib-unload.exp
+++ b/gdb/testsuite/gdb.base/shlib-unload.exp
@@ -225,6 +225,75 @@ proc_with_prefix test_dprintf_with_rerun {} {
"dprintf is non-pending after restart"
}
+# Check that we see breakpoint modified events (where appropriate)
+# when the 'nosharedlibrary' command is used to unload all shared
+# libraries.
+#
+# Also check that the 'nosharedlibrary' doesn't trigger a warning
+# about shared library breakpoints being disabled.
+proc_with_prefix test_silent_nosharedlib {} {
+ if { ![allow_python_tests] } {
+ unsupported "python support needed"
+ return
+ }
+
+ foreach_with_prefix type { breakpoint dprintf } {
+ clean_restart $::binfile
+
+ if {![runto_main]} {
+ return
+ }
+
+ gdb_breakpoint $::srcfile:$::bp_line
+ gdb_continue_to_breakpoint "stop before dlclose"
+
+ # Setup a dprintf or breakpoint in the shared library.
+ if { $type eq "breakpoint" } {
+ gdb_test "break foo"
+ } else {
+ gdb_test "dprintf foo,\"In foo\""
+ }
+
+ # Record the number of the b/p (or dprintf) we just inserted.
+ set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
+ "get b/p number"]
+
+ # Load Python library to track b/p modifications.
+ gdb_test_no_output "source $::pyfile" "import python scripts"
+
+ # Initialise the b/p modified hash. Currently dprintf style
+ # breakpoints are not visible from Python, so the modification
+ # count will remain unchanged in that case.
+ gdb_test_no_output "python bp_modified_counts\[$bp_num\] = 0"
+
+ # Discard symbols from all loaded shared libraries.
+ gdb_test_no_output "nosharedlibrary"
+
+ # Check that our b/p is now showing as disabled.
+ if { $type eq "breakpoint" } {
+ set re \
+ [list "$bp_num\\s+breakpoint\\s+keep\\s+y\\s+<PENDING>\\s+foo"]
+ set count 1
+ } else {
+ set re \
+ [list \
+ "$bp_num\\s+dprintf\\s+keep\\s+y\\s+<PENDING>\\s+foo" \
+ "\\s+printf \"In foo\""]
+ set count 0
+ }
+
+ gdb_test "info breakpoints $bp_num" \
+ [multi_line "^Num\\s+Type\\s+Disp\\s+Enb\\s+Address\\s+What" \
+ {*}$re]
+
+ # Check we've seen the expected number of breakpoint modified
+ # events. Currently dprintf breakpoints are not visible from
+ # Python, so we will not see an event in that case.
+ gdb_test "python print(bp_modified_counts\[$bp_num\])" "^$count"
+ }
+}
+
test_bp_modified_events
test_dprintf_after_unload
test_dprintf_with_rerun
+test_silent_nosharedlib
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
index 3e76d38..ddad628 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-anonymous.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
index 505a4e1..c7d15ce 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-array-decay.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++ additional_flags=-std=c++11}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
index 1a5f60a..9ef1e83 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-inherit.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-member.exp b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
index 5ffbb30..ac9111c 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-member.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-member.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-method.exp b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
index 0a0e0fa..bcbfbb0 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-method.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-method.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
index 3ab8ece..2abc366 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-namespace.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
index 19efd4f..247d270 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-nested.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-print.exp b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
index 594f94a..e4413f0 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-print.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-print.exp
@@ -19,6 +19,8 @@ standard_testfile
require is_c_compiler_gcc
+require allow_compile_tests
+
set options {}
if [test_compiler_info gcc*] {
lappend options additional_flags=-g3
diff --git a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
index 8761df5..a770208 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus-virtual.exp
@@ -23,6 +23,8 @@ require allow_cplus_tests
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[prepare_for_testing $testfile $testfile $srcfile \
{debug nowarnings c++}]} {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile-cplus.exp b/gdb/testsuite/gdb.compile/compile-cplus.exp
index 711f299..35ae692 100644
--- a/gdb/testsuite/gdb.compile/compile-cplus.exp
+++ b/gdb/testsuite/gdb.compile/compile-cplus.exp
@@ -19,6 +19,8 @@ standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
require is_c_compiler_gcc
+require allow_compile_tests
+
set options {}
if { [test_compiler_info gcc*] || [test_compiler_info clang*] } {
lappend options additional_flags=-g3
diff --git a/gdb/testsuite/gdb.compile/compile-ifunc.exp b/gdb/testsuite/gdb.compile/compile-ifunc.exp
index b004bd7..e490890 100644
--- a/gdb/testsuite/gdb.compile/compile-ifunc.exp
+++ b/gdb/testsuite/gdb.compile/compile-ifunc.exp
@@ -17,6 +17,8 @@ load_lib compile-support.exp
require allow_ifunc_tests
+require allow_compile_tests
+
standard_testfile
require is_c_compiler_gcc
diff --git a/gdb/testsuite/gdb.compile/compile-ops.exp b/gdb/testsuite/gdb.compile/compile-ops.exp
index f75e02c..cfbe2b0 100644
--- a/gdb/testsuite/gdb.compile/compile-ops.exp
+++ b/gdb/testsuite/gdb.compile/compile-ops.exp
@@ -22,6 +22,8 @@ load_lib dwarf.exp
# This test can only be run on targets which support DWARF-2 and use gas.
require dwarf2_support
+require allow_compile_tests
+
require is_c_compiler_gcc
standard_testfile .c -dbg.S
diff --git a/gdb/testsuite/gdb.compile/compile-print.exp b/gdb/testsuite/gdb.compile/compile-print.exp
index f8f2297..61ce750 100644
--- a/gdb/testsuite/gdb.compile/compile-print.exp
+++ b/gdb/testsuite/gdb.compile/compile-print.exp
@@ -19,6 +19,8 @@ standard_testfile
require is_c_compiler_gcc
+require allow_compile_tests
+
if { [prepare_for_testing "failed to prepare" "$testfile"] } {
return -1
}
diff --git a/gdb/testsuite/gdb.compile/compile-setjmp.exp b/gdb/testsuite/gdb.compile/compile-setjmp.exp
index f387a05..ad8732b 100644
--- a/gdb/testsuite/gdb.compile/compile-setjmp.exp
+++ b/gdb/testsuite/gdb.compile/compile-setjmp.exp
@@ -19,6 +19,8 @@ standard_testfile .c compile-setjmp-mod.c
require is_c_compiler_gcc
+require allow_compile_tests
+
if { [prepare_for_testing "failed to prepare" $testfile] } {
return -1
}
diff --git a/gdb/testsuite/gdb.compile/compile-tls.exp b/gdb/testsuite/gdb.compile/compile-tls.exp
index 2f8dc5a..45e290e 100644
--- a/gdb/testsuite/gdb.compile/compile-tls.exp
+++ b/gdb/testsuite/gdb.compile/compile-tls.exp
@@ -19,6 +19,8 @@ standard_testfile .c
require is_c_compiler_gcc
+require allow_compile_tests
+
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
executable {debug}] != "" } {
return -1
diff --git a/gdb/testsuite/gdb.compile/compile.exp b/gdb/testsuite/gdb.compile/compile.exp
index 2c2e321..5128dc62 100644
--- a/gdb/testsuite/gdb.compile/compile.exp
+++ b/gdb/testsuite/gdb.compile/compile.exp
@@ -15,6 +15,8 @@
load_lib compile-support.exp
+require allow_compile_tests
+
standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
require is_c_compiler_gcc
diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c b/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c
new file mode 100644
index 0000000..70fc328
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified-lib.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ 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/>. */
+
+int
+foo (void)
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified.c b/gdb/testsuite/gdb.mi/mi-dprintf-modified.c
new file mode 100644
index 0000000..7a41adbac
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified.c
@@ -0,0 +1,55 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ 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/>. */
+
+#include <stdlib.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (TEXT (name))
+#ifdef _WIN32_WCE
+# define dlsym(handle, func) GetProcAddress (handle, TEXT (func))
+#else
+# define dlsym(handle, func) GetProcAddress (handle, func)
+#endif
+#define dlclose(handle) FreeLibrary (handle)
+#else
+#include <dlfcn.h>
+#endif
+
+#include <assert.h>
+
+int
+main (void)
+{
+ int res;
+ void *handle;
+ int (*func) (void);
+ int val = 0;
+
+ handle = dlopen (SHLIB_NAME, RTLD_LAZY); /* Break here. */
+ assert (handle != NULL);
+
+ func = (int (*)(void)) dlsym (handle, "foo");
+ assert (func != NULL);
+
+ val += func ();
+
+ res = dlclose (handle);
+ assert (res == 0);
+
+ return val;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp b/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp
new file mode 100644
index 0000000..c3e1bdf
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-dprintf-modified.exp
@@ -0,0 +1,119 @@
+# 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/>.
+
+# Check that GDB doesn't emit a 'breakpoint-modified' notification for
+# dprintf breakpoints when the dprintf commands haven't changed.
+#
+# GDB use to emit a 'breakpoint-modified' dprintf breakpoints each
+# time the dprintf_breakpoint::re_set function was called as this
+# would re-cacluate the dprintf command string, even though in most
+# cases the calculated string was no different from the previous
+# value.
+#
+# Then GDB got smarter and could recognise that the string had not
+# changed, and so would skip the 'breakpoint-modified' notification.
+#
+# This test stops at a dlopen() call in the inferior and creates a
+# dprintf breakpoint. Then we 'next' over the dlopen() which triggers
+# a call to the ::re_set() functions. We check that there is no
+# 'breakpoint-modified' event emitted for the dprintf breakpoint.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile .c -lib.c
+
+# Build the library.
+set libname ${testfile}-lib
+set libfile [standard_output_file $libname]
+if { [build_executable "build shlib" $libfile $srcfile2 {debug shlib}] == -1} {
+ return
+}
+
+# Build the executable.
+set opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${libname}\"]
+if { [build_executable "build exec" $binfile $srcfile $opts] == -1} {
+ return
+}
+
+# The line number of the dlopen() call.
+set bp_line [gdb_get_line_number "Break here" $srcfile]
+
+# Start the inferior.
+mi_clean_restart $binfile
+mi_runto_main
+
+# Place a breakpoint at the dlopen() line.
+mi_create_breakpoint $srcfile:$bp_line "set breakpoint at dlopen call" \
+ -disp keep -func main -file "\[^\r\n\]+/$srcfile" -line $bp_line
+
+# And run to the breakpoint.
+mi_execute_to "exec-continue" "breakpoint-hit" main "" ".*/$srcfile" \
+ $bp_line { "" "disp=\"keep\"" } "run to breakpoint"
+
+# Cleanup breakpoints.
+mi_delete_breakpoints
+
+# Setup a dprintf breakpoint.
+mi_gdb_test "-dprintf-insert --function main \"in main\"" \
+ "\\^done,bkpt={.*}" "dprintf at main"
+
+set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID" \
+ "get number for dprintf breakpoint"]
+
+# Use 'next' to step over loading the shared library.
+mi_gdb_test "220-exec-next" ".*" "next over dlopen"
+
+# Now wait for the 'stopped' notification. While we wait we should
+# see a 'library-loaded' notification for the loading of the shared
+# library.
+#
+# In older versions of GDB we would also see a 'breakpoint-modified'
+# notification for the dprintf breakpoint, but newer versions of GDB
+# are smart enough to not emit this unnecessary notification.
+set bp_re [mi_make_breakpoint -number $bpnum \
+ -type dprintf -disp keep -enabled y -func main]
+set saw_bp_modified false
+set saw_lib_load false
+set saw_stopped false
+gdb_test_multiple "" "wait for 'next' to complete" {
+ -re "^=library-loaded,id=\[^\r\n\]+\r\n" {
+ set saw_lib_load true
+ exp_continue
+ }
+
+ -re "^=breakpoint-modified,$bp_re\r\n" {
+ set saw_bp_modified true
+ exp_continue
+ }
+
+ -re "^\\*stopped,reason=\"end-stepping-range\",\[^\r\n\]+\r\n" {
+ set saw_stopped true
+ exp_continue
+ }
+
+ -re "^$mi_gdb_prompt$" {
+ gdb_assert { $saw_lib_load } \
+ "$gdb_test_name, library was loaded"
+ gdb_assert { $saw_stopped } \
+ "$gdb_test_name, saw stopped message"
+ gdb_assert { !$saw_bp_modified } \
+ "$gdb_test_name, no breakpoint-modified"
+ }
+
+ -re "^\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+}
diff --git a/gdb/testsuite/gdb.testsuite/version-compare.exp b/gdb/testsuite/gdb.testsuite/version-compare.exp
new file mode 100644
index 0000000..8f2573e
--- /dev/null
+++ b/gdb/testsuite/gdb.testsuite/version-compare.exp
@@ -0,0 +1,74 @@
+# 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/>.
+
+# Check version_compare proc.
+
+proc eq { a b } {
+ with_test_prefix "$a == $b" {
+ gdb_assert { [version_compare $a == $b] }
+ gdb_assert { [version_compare $a <= $b] }
+ gdb_assert { [version_compare $a >= $b] }
+ gdb_assert { ![version_compare $a < $b] }
+ gdb_assert { ![version_compare $a > $b] }
+ }
+}
+
+proc lt { a b } {
+ with_test_prefix "$a < $b" {
+ gdb_assert { [version_compare $a < $b] }
+ gdb_assert { [version_compare $a <= $b] }
+ gdb_assert { [version_compare $b > $a] }
+ gdb_assert { [version_compare $b >= $a] }
+ gdb_assert { ![version_compare $a == $b] }
+ gdb_assert { ![version_compare $b == $a] }
+ gdb_assert { ![version_compare $a > $b] }
+ gdb_assert { ![version_compare $a >= $b] }
+ gdb_assert { ![version_compare $b < $a] }
+ gdb_assert { ![version_compare $b <= $a] }
+ }
+}
+
+# Equal, same length.
+eq {1 0} {1 0}
+
+# Smaller than, same length.
+lt {1 0} {1 1}
+lt {1 1} {2 0}
+
+# Smaller than, different length.
+lt {1 3} {2}
+lt {1} {2 0}
+
+# The question how v1 and v1.0 relate to each other is not a trivial one.
+#
+# For instance, Python considers v1 == v1.0:
+# $ test.py
+# #!/usr/bin/python3
+# from packaging.version import parse
+# v1_0 = parse("1.0")
+# v1 = parse("1")
+# print (v1 == v1_0)
+# $ ./test.py
+# True
+#
+# OTOH, version sort from coreutils considers v1 < v1.0:
+# $ cat bla.txt
+# 1.0
+# 1
+# $ sort -V bla.txt
+# 1
+# 1.0
+#
+# Proc version_compare seems to have taken the latter approach.
+lt {1} {1 0}
diff --git a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c
index af05b13..e22bf12 100644
--- a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c
+++ b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.c
@@ -97,6 +97,11 @@ thread_fn (void *arg)
return NULL;
}
+static void
+setup_done (void)
+{
+}
+
int
main (void)
{
@@ -104,6 +109,8 @@ main (void)
global_var++;
+ setup_done ();
+
for (i = 0; i < 4; i++)
{
struct thread_arg *p;
diff --git a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp
index 784f17f..42222c0 100644
--- a/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp
+++ b/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp
@@ -54,7 +54,7 @@ proc test { non_stop } {
clean_restart ${binfile}
}
- if ![runto_main] {
+ if ![runto setup_done] {
return -1
}
@@ -76,7 +76,7 @@ proc test { non_stop } {
# Start the second inferior.
with_test_prefix "second inferior" {
# With stub targets that do reload on run, if we let the new
- # inferior share inferior 1's connection, runto_main would
+ # inferior share inferior 1's connection, runto would
# fail because GDB is already connected to something, like
# e.g. with --target_board=native-gdbserver:
#
@@ -86,10 +86,10 @@ proc test { non_stop } {
# Already connected to a remote target. Disconnect? (y or n)
#
# Instead, start the inferior with no connection, and let
- # gdb_load/runto_main spawn a new remote connection/gdbserver.
+ # gdb_load/runto spawn a new remote connection/gdbserver.
#
# OTOH, with extended-remote, we must let the new inferior
- # reuse the current connection, so that runto_main below can
+ # reuse the current connection, so that runto below can
# issue the "run" command, and have the inferior run on the
# remote target. If we forced no connection, then "run" would
# either fail if "set auto-connect-native-target" is on, like
@@ -108,7 +108,7 @@ proc test { non_stop } {
gdb_load $binfile
- if ![runto_main] {
+ if ![runto setup_done] {
return -1
}
}
diff --git a/gdb/testsuite/lib/ada.exp b/gdb/testsuite/lib/ada.exp
index 0a1231b..e1a3a23 100644
--- a/gdb/testsuite/lib/ada.exp
+++ b/gdb/testsuite/lib/ada.exp
@@ -181,12 +181,16 @@ proc find_ada_tool {tool} {
# compiler does not appear to be GCC, this will always return false.
proc gnat_version_compare {op l2} {
- set gccvers [gcc_major_version]
- if {$gccvers == -1} {
+ set gnatmake [find_gnatmake]
+ set gnatmake [lindex [split $gnatmake] 0]
+ if {[catch {exec $gnatmake --version} output]} {
+ return 0
+ }
+ if {![regexp {GNATMAKE ([0-9]+(\.[0-9]+)*)} $output match version]} {
return 0
}
- return [version_compare [split $gccvers .] $op $l2]
+ return [version_compare [split $version .] $op $l2]
}
# Return 1 if the GNAT runtime appears to have debug info.
diff --git a/gdb/testsuite/lib/compile-support.exp b/gdb/testsuite/lib/compile-support.exp
index aa8aaf3..6d7a4ce 100644
--- a/gdb/testsuite/lib/compile-support.exp
+++ b/gdb/testsuite/lib/compile-support.exp
@@ -45,6 +45,9 @@ proc _do_check_compile {expr} {
# This appears to be a bug in the compiler plugin.
set result "apparent compiler plugin bug"
}
+ -re "This command is not supported." {
+ set result "compiler disabled at configure time"
+ }
-re "\r\n$gdb_prompt $" {
}
}
diff --git a/gdb/testsuite/lib/gdb-utils.exp b/gdb/testsuite/lib/gdb-utils.exp
index b8ab30a..f32f533 100644
--- a/gdb/testsuite/lib/gdb-utils.exp
+++ b/gdb/testsuite/lib/gdb-utils.exp
@@ -117,7 +117,10 @@ proc gdb_get_bp_addr { num } {
# Compare the version numbers in L1 to those in L2 using OP, and
# return 1 if the comparison is true. OP can be "<", "<=", ">", ">=",
-# or "==". It is ok if the lengths of the lists differ.
+# or "==".
+# It is ok if the lengths of the lists differ, but note that we have
+# "{1} < {1 0}" instead of "{1} == {1 0}". See also
+# gdb.testsuite/version-compare.exp.
proc version_compare { l1 op l2 } {
switch -exact $op {
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 3349da7..59967c7 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2799,6 +2799,12 @@ gdb_caching_proc allow_python_tests {} {
return [expr {[string first "--with-python" $output] != -1}]
}
+# Return a 1 if GDB was configured to support compile commands.
+gdb_caching_proc allow_compile_tests {} {
+ set output [remote_exec host $::GDB "$::INTERNAL_GDBFLAGS -ex \"compile int x = 1\" -batch"]
+ return [expr {[string first "The program must be running" $output] != -1}]
+}
+
# Return a 1 for configurations that use system readline rather than the
# in-repo copy.
@@ -3931,13 +3937,16 @@ gdb_caching_proc is_aarch32_target {} {
return 0
}
- set list {}
- foreach reg \
- {r0 r1 r2 r3} {
- lappend list "\tmov $reg, $reg"
- }
+ return [gdb_can_simple_compile aarch32 {
+ int main (void) {
+ asm ("\tmov r0, r0");
+ asm ("\tmov r1, r1");
+ asm ("\tmov r2, r2");
+ asm ("\tmov r3, r3");
- return [gdb_can_simple_compile aarch32 [join $list \n]]
+ return 0;
+ }
+ }]
}
# Return 1 if this target is an aarch64, either lp64 or ilp32.
@@ -5940,6 +5949,23 @@ proc gdb_compile {source dest type options} {
}
}
+ # On AIX systems, until GCC 12 (maybe later), stabs was the default
+ # debug option, but we'd like to have dwarf instead.
+ # If we're running on one of those systems and debug was requested,
+ # but no explicit -g<format> option was given, use -gdwarf to force
+ # that as the debug info for the inferior.
+ # This list should be exhaustive:
+ set debug_format "btf|ctf|stabs|vms|coff|xcoff"
+ # Since additional_flags is a comma separated list, identify if there
+ # are other (optional) flags in the list.
+ set other_options "-\[a-zA-Z0-9\]*,"
+ set full_regexp "^additional_flags=\($other_options\)*-g\($debug_format\)"
+ if { [istarget *-*-aix*]
+ && [lsearch -exact $options debug] != -1
+ && [lsearch -regexp $options $full_regexp] == -1} {
+ lappend new_options "additional_flags=-gdwarf"
+ }
+
set shlib_found 0
set shlib_load 0
foreach opt $options {
diff --git a/gdb/top.c b/gdb/top.c
index b2575bc..80d0ec5 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -381,7 +381,7 @@ check_frame_language_change (void)
/* Warn the user if the working language does not match the language
of the current frame. Only warn the user if we are actually
running the program, i.e. there is a stack. */
- /* FIXME: This should be cacheing the frame and only running when
+ /* FIXME: This should be caching the frame and only running when
the frame changes. */
if (warn_frame_lang_mismatch && has_stack_frames ())
diff --git a/gdb/utils.c b/gdb/utils.c
index ee7cf4d..2244b90 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -382,7 +382,7 @@ internal_vproblem (struct internal_problem *problem,
#endif
/* Create a string containing the full error/warning message. Need
- to call query with this full string, as otherwize the reason
+ to call query with this full string, as otherwise the reason
(error/warning) and question become separated. Format using a
style similar to a compiler error message. Include extra detail
so that the user knows that they are living on the edge. */
diff --git a/gdb/value.c b/gdb/value.c
index ddc0959..d4548b8 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -107,7 +107,7 @@ ranges_contain (const std::vector<range> &ranges, LONGEST offset,
range, we can do a binary search for the position the given range
would be inserted if we only considered the starting OFFSET of
ranges. We call that position I. Since we also have LENGTH to
- care for (this is a range afterall), we need to check if the
+ care for (this is a range after all), we need to check if the
_previous_ range overlaps the I range. E.g.,
R
@@ -267,7 +267,7 @@ insert_into_bit_range_vector (std::vector<range> *vectorp,
/* Do a binary search for the position the given range would be
inserted if we only considered the starting OFFSET of ranges.
Call that position I. Since we also have LENGTH to care for
- (this is a range afterall), we need to check if the _previous_
+ (this is a range after all), we need to check if the _previous_
range overlaps the I range. E.g., calling R the new range:
#1 - overlaps with previous
@@ -2833,7 +2833,7 @@ value_as_address (struct value *val)
#endif
}
-/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+/* Unpack raw data (copied from debuggee, target byte order) at VALADDR
as a long, or as a double, assuming the raw data is described
by type TYPE. Knows how to convert different sizes of values
and can convert between fixed and floating point. We don't assume
@@ -2924,7 +2924,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
}
}
-/* Unpack raw data (copied from debugee, target byte order) at VALADDR
+/* Unpack raw data (copied from debuggee, target byte order) at VALADDR
as a CORE_ADDR, assuming the raw data is described by type TYPE.
We don't assume any alignment for the raw data. Return value is in
host byte order.
diff --git a/gdb/value.h b/gdb/value.h
index 8e5fd54..bb6005b 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -961,7 +961,7 @@ struct lval_funcs
This may simply return the same closure, if VALUE's is
reference-counted or statically allocated.
- This may be NULL, in which case VALUE's closure is re-used in the
+ This may be NULL, in which case VALUE's closure is reused in the
new value. */
void *(*copy_closure) (const struct value *v);
diff --git a/gdb/varobj.c b/gdb/varobj.c
index dcadce1..cf27b1e 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -1309,7 +1309,7 @@ install_new_value (struct varobj *var, struct value *value, bool initial)
{
/* For values that are not changeable, we don't compare the values.
However, we want to notice if a value was not NULL and now is NULL,
- or vise versa, so that we report when top-level varobjs come in scope
+ or vice versa, so that we report when top-level varobjs come in scope
and leave the scope. */
changed = (var->value != NULL) != (value != NULL);
}
diff --git a/gdb/vax-tdep.c b/gdb/vax-tdep.c
index 4660979..64ade0a 100644
--- a/gdb/vax-tdep.c
+++ b/gdb/vax-tdep.c
@@ -438,7 +438,7 @@ vax_frame_num_args (const frame_info_ptr &frame)
-/* Initialize the current architecture based on INFO. If possible, re-use an
+/* Initialize the current architecture based on INFO. If possible, reuse an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index b36e7f4..cd253e3 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -25,14 +25,14 @@ typedef int (segment_register_p_ftype) (int regnum);
/* segment_register_p_ftype implementation for x86. */
int i386_windows_segment_register_p (int regnum);
-/* context register offests for x86. */
+/* context register offsets for x86. */
extern const int i386_mappings[];
#ifdef __x86_64__
/* segment_register_p_ftype implementation for amd64. */
int amd64_windows_segment_register_p (int regnum);
-/* context register offests for amd64. */
+/* context register offsets for amd64. */
extern const int amd64_mappings[];
#endif
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 2ff9d4a..233988d 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -970,7 +970,7 @@ read_xcoff_symtab (struct objfile *objfile, legacy_psymtab *pst)
while (symnum < max_symnum)
{
- QUIT; /* make this command interruptable. */
+ QUIT; /* make this command interruptible. */
/* READ_ONE_SYMBOL (symbol, cs, symname_alloced); */
/* read one symbol into `cs' structure. After processing the
@@ -1371,7 +1371,7 @@ read_xcoff_symtab (struct objfile *objfile, legacy_psymtab *pst)
case C_BINCL:
/* beginning of include file */
/* In xlc output, C_BINCL/C_EINCL pair doesn't show up in sorted
- order. Thus, when wee see them, we might not know enough info
+ order. Thus, when we see them, we might not know enough info
to process them. Thus, we'll be saving them into a table
(inclTable) and postpone their processing. */
diff --git a/gdb/xstormy16-tdep.c b/gdb/xstormy16-tdep.c
index e7f4e6f..43176d9 100644
--- a/gdb/xstormy16-tdep.c
+++ b/gdb/xstormy16-tdep.c
@@ -435,7 +435,7 @@ xstormy16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
return sal.end;
}
}
- /* No useable line symbol. Use result of prologue parsing method. */
+ /* No usable line symbol. Use result of prologue parsing method. */
return plg_end;
}
diff --git a/gdb/xtensa-tdep.c b/gdb/xtensa-tdep.c
index c87940c..074b748 100644
--- a/gdb/xtensa-tdep.c
+++ b/gdb/xtensa-tdep.c
@@ -1767,7 +1767,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
arg_type = builtin_type (gdbarch)->builtin_long;
arg = value_cast (arg_type, arg);
}
- /* Aligment is equal to the type length for the basic types. */
+ /* Alignment is equal to the type length for the basic types. */
info->align = arg_type->length ();
break;