aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/elfxx-aarch64.c2
-rw-r--r--bfd/version.h2
-rw-r--r--binutils/MAINTAINERS1
-rw-r--r--binutils/doc/binutils.texi21
-rw-r--r--binutils/objcopy.c115
-rw-r--r--binutils/resbin.c10
-rw-r--r--binutils/testsuite/binutils-all/objcopy.exp8
-rw-r--r--gas/config/obj-elf.c2
-rw-r--r--gas/dwarf2dbg.c32
-rw-r--r--gas/ehopt.c47
-rw-r--r--gas/testsuite/gas/aarch64/gpc3.d11
-rw-r--r--gas/testsuite/gas/aarch64/gpc3.s7
-rw-r--r--gas/testsuite/gas/aarch64/occmo.d18
-rw-r--r--gas/testsuite/gas/aarch64/occmo.s8
-rw-r--r--gdb/NEWS25
-rw-r--r--gdb/break-cond-parse.c13
-rw-r--r--gdb/c-exp.y4
-rw-r--r--gdb/doc/gdb.texinfo10
-rw-r--r--gdb/doc/guile.texi6
-rw-r--r--gdb/doc/python.texi99
-rw-r--r--gdb/dwarf2/dwz.c58
-rw-r--r--gdb/dwarf2/read.c93
-rw-r--r--gdb/dwarf2/read.h3
-rw-r--r--gdb/guile/scm-cmd.c2
-rw-r--r--gdb/guile/scm-param.c41
-rw-r--r--gdb/linux-tdep.c128
-rw-r--r--gdb/loongarch-tdep.c18
-rw-r--r--gdb/python/lib/gdb/__init__.py118
-rw-r--r--gdb/python/lib/gdb/dap/sources.py6
-rw-r--r--gdb/python/py-cmd.c2
-rw-r--r--gdb/python/py-param.c18
-rw-r--r--gdb/symtab.c7
-rw-r--r--gdb/symtab.h6
-rw-r--r--gdb/testsuite/gdb.base/foll-fork-syscall.c35
-rw-r--r--gdb/testsuite/gdb.base/foll-fork-syscall.exp142
-rw-r--r--gdb/testsuite/gdb.base/options.exp16
-rw-r--r--gdb/testsuite/gdb.guile/scm-cmd.exp59
-rw-r--r--gdb/testsuite/gdb.guile/scm-parameter.exp112
-rw-r--r--gdb/testsuite/gdb.multi/tids.exp4
-rw-r--r--gdb/testsuite/gdb.python/py-cmd.exp27
-rw-r--r--gdb/testsuite/gdb.python/py-parameter-prefix.exp285
-rw-r--r--gdb/testsuite/gdb.python/py-parameter.exp125
-rw-r--r--gdb/testsuite/gdb.threads/current-lwp-dead.exp2
-rw-r--r--gdb/testsuite/gdb.threads/info-threads-options.c77
-rw-r--r--gdb/testsuite/gdb.threads/info-threads-options.exp131
-rw-r--r--gdb/testsuite/gdb.threads/thread-bp-deleted.exp2
-rw-r--r--gdb/testsuite/lib/gdb.exp5
-rw-r--r--gdb/thread.c122
-rw-r--r--gdbsupport/event-loop.cc3
-rw-r--r--ld/testsuite/ld-elfvers/vers7.c4
-rw-r--r--ld/testsuite/ld-plugin/lto-binutils.exp339
-rw-r--r--ld/testsuite/ld-plugin/lto.exp5
-rw-r--r--ld/testsuite/ld-plugin/strip-1a-fat.c1
-rw-r--r--ld/testsuite/ld-plugin/strip-1a-fat.rd6
-rw-r--r--ld/testsuite/ld-plugin/strip-1a.c4
-rw-r--r--ld/testsuite/ld-plugin/strip-1b-fat.c1
-rw-r--r--ld/testsuite/ld-plugin/strip-1b-fat.rd5
-rw-r--r--ld/testsuite/ld-plugin/strip-1b.c3
-rw-r--r--ld/testsuite/lib/ld-lib.exp9
-rw-r--r--opcodes/aarch64-opc.c4
-rw-r--r--opcodes/aarch64-sys-regs.def1
-rw-r--r--opcodes/aarch64-tbl.h14
62 files changed, 2145 insertions, 339 deletions
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 68e004ef..551f74e 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -708,7 +708,7 @@ static inline bool
bfd_is_non_dynamic_elf_object (bfd *abfd, const struct elf_backend_data *out_be)
{
const struct elf_backend_data *in_be = get_elf_backend_data (abfd);
-
+
return bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& bfd_count_sections (abfd) != 0
&& (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0
diff --git a/bfd/version.h b/bfd/version.h
index 2fe8d9a..eab1fea 100644
--- a/bfd/version.h
+++ b/bfd/version.h
@@ -16,7 +16,7 @@
In releases, the date is not included in either version strings or
sonames. */
-#define BFD_VERSION_DATE 20250510
+#define BFD_VERSION_DATE 20250514
#define BFD_VERSION @bfd_version@
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
#define REPORT_BUGS_TO @report_bugs_to@
diff --git a/binutils/MAINTAINERS b/binutils/MAINTAINERS
index 643a604..993a36e 100644
--- a/binutils/MAINTAINERS
+++ b/binutils/MAINTAINERS
@@ -63,7 +63,6 @@ maintainer. The first maintainer is free to devolve that
responsibility among the other maintainers.
AARCH64 Richard Earnshaw <rearnsha@arm.com>
- AARCH64 Marcus Shawcroft <marcus.shawcroft@arm.com>
ARC Claudiu Zissulescu <claziss@gmail.com>
ARM Nick Clifton <nickc@redhat.com>
ARM Richard Earnshaw <rearnsha@arm.com>
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 7f041d9..d094f7d 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -3566,6 +3566,7 @@ strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname}]
[@option{--keep-section-symbols}]
[@option{--keep-file-symbols}]
[@option{--only-keep-debug}]
+ [@option{--plugin} @var{name}]
[@option{-v} |@option{--verbose}] [@option{-V}|@option{--version}]
[@option{--help}] [@option{--info}]
@var{objfile}@dots{}
@@ -3825,6 +3826,26 @@ currently only supports the presence of one filename containing
debugging information, not multiple filenames on a one-per-object-file
basis.
+@item --plugin @var{name}
+@cindex plugins
+Load the plugin called @var{name} to add support for extra target
+types. This option is only available if the toolchain has been built
+with plugin support enabled.
+
+If @option{--plugin} is not provided, but plugin support has been
+enabled then @command{strip} iterates over the files in
+@file{$@{libdir@}/bfd-plugins} in alphabetic order and the first
+plugin that claims the object in question is used.
+
+Please note that this plugin search directory is @emph{not} the one
+used by @command{ld}'s @option{-plugin} option. In order to make
+@command{strip} use the linker plugin it must be copied into the
+@file{$@{libdir@}/bfd-plugins} directory. For GCC based compilations
+the linker plugin is called @file{liblto_plugin.so.0.0.0}. For Clang
+based compilations it is called @file{LLVMgold.so}. The GCC plugin
+is always backwards compatible with earlier versions, so it is
+sufficient to just copy the newest one.
+
@item -V
@itemx --version
Show the version number for @command{strip}.
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 31933e1..a973789 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -30,6 +30,8 @@
#include "coff/internal.h"
#include "libcoff.h"
#include "safe-ctype.h"
+#include "plugin-api.h"
+#include "plugin.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
header in generic PE code. */
@@ -165,6 +167,11 @@ static struct section_list *change_sections;
/* TRUE if some sections are to be removed. */
static bool sections_removed;
+#if BFD_SUPPORTS_PLUGINS
+/* TRUE if all GCC LTO sections are to be removed. */
+static bool lto_sections_removed;
+#endif
+
/* TRUE if only some sections are to be copied. */
static bool sections_copied;
@@ -359,6 +366,7 @@ enum command_line_switch
OPTION_RENAME_SECTION,
OPTION_REVERSE_BYTES,
OPTION_PE_SECTION_ALIGNMENT,
+ OPTION_PLUGIN,
OPTION_SET_SECTION_FLAGS,
OPTION_SET_SECTION_ALIGNMENT,
OPTION_SET_START,
@@ -402,6 +410,7 @@ static struct option strip_options[] =
{"output-file", required_argument, 0, 'o'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
+ {"plugin", required_argument, 0, OPTION_PLUGIN},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
{"remove-relocations", required_argument, 0, OPTION_REMOVE_RELOCS},
@@ -758,6 +767,10 @@ strip_usage (FILE *stream, int exit_status)
--info List object formats & architectures supported\n\
-o <file> Place stripped output into <file>\n\
"));
+#if BFD_SUPPORTS_PLUGINS
+ fprintf (stream, _("\
+ --plugin NAME Load the specified plugin\n"));
+#endif
list_supported_targets (program_name, stream);
if (REPORT_BUGS_TO[0] && exit_status == 0)
@@ -1916,20 +1929,11 @@ add_redefine_syms_file (const char *filename)
Returns TRUE upon success, FALSE otherwise. */
static bool
-copy_unknown_object (bfd *ibfd, bfd *obfd)
+copy_unknown_file (bfd *ibfd, bfd *obfd, off_t size, unsigned int mode)
{
char *cbuf;
bfd_size_type tocopy;
- off_t size;
- struct stat buf;
- if (bfd_stat_arch_elt (ibfd, &buf) != 0)
- {
- bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
- return false;
- }
-
- size = buf.st_size;
if (size < 0)
{
non_fatal (_("stat returns negative size for `%s'"),
@@ -1974,11 +1978,31 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
/* We should at least to be able to read it back when copying an
unknown object in an archive. */
- chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
+ chmod (bfd_get_filename (obfd), mode | S_IRUSR);
free (cbuf);
return true;
}
+/* Copy unknown object file archive member IBFD onto OBFD.
+ Returns TRUE upon success, FALSE otherwise. */
+
+static bool
+copy_unknown_object (bfd *ibfd, bfd *obfd)
+{
+ struct stat buf;
+
+ if (bfd_stat_arch_elt (ibfd, &buf) != 0)
+ {
+ bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
+ return false;
+ }
+
+ if (!copy_unknown_file (ibfd, obfd, buf.st_size, buf.st_mode))
+ return false;
+
+ return true;
+}
+
typedef struct objcopy_internal_note
{
Elf_Internal_Note note;
@@ -3744,6 +3768,12 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
goto cleanup_and_exit;
}
+#if BFD_SUPPORTS_PLUGINS
+ /* Copy LTO IR file as unknown object. */
+ if (bfd_plugin_target_p (ibfd->xvec))
+ ok_object = false;
+ else
+#endif
if (ok_object)
{
ok = copy_object (this_element, output_element, input_arch);
@@ -3845,6 +3875,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
char **obj_matching;
char **core_matching;
off_t size = get_file_size (input_filename);
+ const char *target = input_target;
if (size < 1)
{
@@ -3855,9 +3886,16 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
return;
}
+#if BFD_SUPPORTS_PLUGINS
+ /* Enable LTO plugin in strip unless all LTO sections should be
+ removed. */
+ if (is_strip && !target && !lto_sections_removed)
+ target = "plugin";
+#endif
+
/* To allow us to do "strip *" without dying on the first
non-object file, failures are nonfatal. */
- ibfd = bfd_openr (input_filename, input_target);
+ ibfd = bfd_openr (input_filename, target);
if (ibfd == NULL || bfd_stat (ibfd, in_stat) != 0)
{
bfd_nonfatal_message (input_filename, NULL, NULL, NULL);
@@ -3974,17 +4012,31 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
return;
}
- if (! copy_object (ibfd, obfd, input_arch))
- status = 1;
-
- /* PR 17512: file: 0f15796a.
- If the file could not be copied it may not be in a writeable
- state. So use bfd_close_all_done to avoid the possibility of
- writing uninitialised data into the file. */
- if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
+#if BFD_SUPPORTS_PLUGINS
+ if (bfd_plugin_target_p (ibfd->xvec))
{
- status = 1;
- bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+ /* Copy LTO IR file as unknown file. */
+ if (!copy_unknown_file (ibfd, obfd, in_stat->st_size,
+ in_stat->st_mode))
+ status = 1;
+ else if (!bfd_close_all_done (obfd))
+ status = 1;
+ }
+ else
+#endif
+ {
+ if (! copy_object (ibfd, obfd, input_arch))
+ status = 1;
+
+ /* PR 17512: file: 0f15796a.
+ If the file could not be copied it may not be in a writeable
+ state. So use bfd_close_all_done to avoid the possibility of
+ writing uninitialised data into the file. */
+ if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
+ {
+ status = 1;
+ bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
+ }
}
if (!bfd_close (ibfd))
@@ -4837,6 +4889,10 @@ strip_main (int argc, char *argv[])
char *output_file = NULL;
bool merge_notes_set = false;
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_program_name (argv[0]);
+#endif
+
while ((c = getopt_long (argc, argv, "I:O:F:K:MN:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
@@ -4927,6 +4983,13 @@ strip_main (int argc, char *argv[])
case OPTION_KEEP_SECTION_SYMBOLS:
keep_section_symbols = true;
break;
+ case OPTION_PLUGIN: /* --plugin */
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_plugin (optarg);
+#else
+ fatal (_("sorry - this program has been built without plugin support\n"));
+#endif
+ break;
case 0:
/* We've been given a long option. */
break;
@@ -4971,6 +5034,14 @@ strip_main (int argc, char *argv[])
if (output_target == NULL)
output_target = input_target;
+#if BFD_SUPPORTS_PLUGINS
+ /* Check if all GCC LTO sections should be removed, assuming all LTO
+ sections will be removed with -R .gnu.lto_.*. * Remove .gnu.lto_.*
+ sections will also remove .gnu.debuglto_. sections. */
+ lto_sections_removed = !!find_section_list (".gnu.lto_.*", false,
+ SECTION_CONTEXT_REMOVE);
+#endif
+
i = optind;
if (i == argc
|| (output_file != NULL && (i + 1) < argc))
diff --git a/binutils/resbin.c b/binutils/resbin.c
index 3bce84f..889126e 100644
--- a/binutils/resbin.c
+++ b/binutils/resbin.c
@@ -1250,7 +1250,7 @@ bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data,
vst = res_alloc (sizeof (rc_ver_stringtable));
- if (!get_version_header (wrbfd, data, length, (const char *) NULL,
+ if (!get_version_header (wrbfd, data, length, "version stringtable",
&vst->language, &stverlen, &vallen,
&type, &off))
return NULL;
@@ -1284,9 +1284,9 @@ bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data,
vs = res_alloc (sizeof (rc_ver_stringinfo));
- if (!get_version_header (wrbfd, data, length,
- (const char *) NULL, &vs->key,
- &sverlen, &vallen, &type, &off))
+ if (!get_version_header (wrbfd, data, length, "version string",
+ &vs->key, &sverlen, &vallen,
+ &type, &off))
return NULL;
data += off;
@@ -1348,7 +1348,7 @@ bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data,
data += off;
length -= off;
- if (!get_version_header (wrbfd, data, length, (const char *) NULL,
+ if (!get_version_header (wrbfd, data, length, "version varfileinfo",
&vi->u.var.key, &verlen, &vallen,
&type, &off))
return NULL;
diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp
index ff93fea..cf94570 100644
--- a/binutils/testsuite/binutils-all/objcopy.exp
+++ b/binutils/testsuite/binutils-all/objcopy.exp
@@ -180,7 +180,7 @@ proc objcopy_test_verilog {testname} {
untested "verilog width-4 and width-8 tests"
return
}
-
+
foreach width {4 8} {
set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width $width $binfile $verilog-$width.hex"]
if ![string equal "" $got] then {
@@ -194,7 +194,7 @@ proc objcopy_test_verilog {testname} {
}
}
- # Test generating endian correct output.
+ # Test generating endian correct output.
set testname "objcopy (verilog output endian-ness == input endian-ness)"
set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width 4 $binfile $verilog-I4.hex"]
if ![string equal "" $got] then {
@@ -202,9 +202,9 @@ proc objcopy_test_verilog {testname} {
}
send_log "regexp_diff $verilog-I4.hex $srcdir/$subdir/verilog-I4.hex\n"
if {! [regexp_diff "$verilog-I4.hex" "$srcdir/$subdir/verilog-I4.hex"]} {
- pass $testname
+ pass $testname
} else {
- fail $testname
+ fail $testname
}
}
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index d37d0fd..bc981f0 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -781,7 +781,7 @@ change_section (const char *name,
|| startswith (name, ".note.gnu"))
flags |= SEC_ELF_OCTETS;
}
-
+
if (old_sec == NULL)
{
symbolS *secsym;
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index 2963e52..e4b21bc 100644
--- a/gas/dwarf2dbg.c
+++ b/gas/dwarf2dbg.c
@@ -678,18 +678,17 @@ get_directory_table_entry (const char *dirname,
}
static bool
-assign_file_to_slot (unsigned int i, const char *file, unsigned int dir)
+assign_file_to_slot (valueT i, const char *file, unsigned int dir)
{
if (i >= files_allocated)
{
unsigned int want = i + 32;
- /* Catch wraparound. */
- if (want < files_allocated
- || want < i
- || want > UINT_MAX / sizeof (struct file_entry))
+ /* If this array is taking 1G or more, someone is using silly
+ file numbers. */
+ if (want < i || want > UINT_MAX / 4 / sizeof (struct file_entry))
{
- as_bad (_("file number %u is too big"), i);
+ as_bad (_("file number %" PRIu64 " is too big"), (uint64_t) i);
return false;
}
@@ -843,7 +842,7 @@ purge_generated_debug (bool thelot)
static bool
allocate_filename_to_slot (const char *dirname,
const char *filename,
- unsigned int num,
+ valueT num,
bool with_md5)
{
const char *file;
@@ -921,8 +920,9 @@ allocate_filename_to_slot (const char *dirname,
}
fail:
- as_bad (_("file table slot %u is already occupied by a different file (%s%s%s vs %s%s%s)"),
- num,
+ as_bad (_("file table slot %u is already occupied by a different file"
+ " (%s%s%s vs %s%s%s)"),
+ (unsigned int) num,
dir == NULL ? "" : dir,
dir == NULL ? "" : "/",
files[num].filename,
@@ -968,7 +968,7 @@ allocate_filename_to_slot (const char *dirname,
d = get_directory_table_entry (dirname, file0_dirname, dirlen, num == 0);
i = num;
- if (! assign_file_to_slot (i, file, d))
+ if (!assign_file_to_slot (num, file, d))
return false;
if (with_md5)
@@ -1228,15 +1228,7 @@ dwarf2_directive_filename (void)
purge_generated_debug (false);
debug_type = DEBUG_NONE;
- if (num != (unsigned int) num
- || num >= (size_t) -1 / sizeof (struct file_entry) - 32)
- {
- as_bad (_("file number %lu is too big"), (unsigned long) num);
- return NULL;
- }
-
- if (! allocate_filename_to_slot (dirname, filename, (unsigned int) num,
- with_md5))
+ if (!allocate_filename_to_slot (dirname, filename, num, with_md5))
return NULL;
return filename;
@@ -1632,7 +1624,7 @@ size_inc_line_addr (int line_delta, addressT addr_delta)
}
/* Bias the line delta by the base. */
- tmp = line_delta - DWARF2_LINE_BASE;
+ tmp = (unsigned) line_delta - DWARF2_LINE_BASE;
/* If the line increment is out of range of a special opcode, we
must encode it with DW_LNS_advance_line. */
diff --git a/gas/ehopt.c b/gas/ehopt.c
index 3e15fc9..ab976ba 100644
--- a/gas/ehopt.c
+++ b/gas/ehopt.c
@@ -90,17 +90,17 @@ __FRAME_BEGIN__:
struct cie_info
{
+ fragS *f;
unsigned code_alignment;
int z_augmentation;
};
/* Extract information from the CIE. */
-static int
+static bool
get_cie_info (struct cie_info *info)
{
fragS *f;
- fixS *fix;
unsigned int offset;
char CIE_id;
char augmentation[10];
@@ -110,9 +110,10 @@ get_cie_info (struct cie_info *info)
/* We should find the CIE at the start of the section. */
f = seg_info (now_seg)->frchainP->frch_root;
- fix = seg_info (now_seg)->frchainP->fix_root;
-
- /* Look through the frags of the section to find the code alignment. */
+ while (f != NULL && f->fr_fix == 0)
+ f = f->fr_next;
+ if (f != info->f)
+ return false;
/* First make sure that the CIE Identifier Tag is 0/-1. */
@@ -133,7 +134,7 @@ get_cie_info (struct cie_info *info)
|| f->fr_literal[offset + 1] != CIE_id
|| f->fr_literal[offset + 2] != CIE_id
|| f->fr_literal[offset + 3] != CIE_id)
- return 0;
+ return false;
/* Next make sure the CIE version number is 1. */
@@ -146,7 +147,7 @@ get_cie_info (struct cie_info *info)
if (f == NULL
|| f->fr_fix - offset < 1
|| f->fr_literal[offset] != 1)
- return 0;
+ return false;
/* Skip the augmentation (a null terminated string). */
@@ -160,7 +161,7 @@ get_cie_info (struct cie_info *info)
f = f->fr_next;
}
if (f == NULL)
- return 0;
+ return false;
while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
{
@@ -181,7 +182,7 @@ get_cie_info (struct cie_info *info)
f = f->fr_next;
}
if (f == NULL)
- return 0;
+ return false;
augmentation[iaug] = '\0';
if (augmentation[0] == '\0')
@@ -192,6 +193,7 @@ get_cie_info (struct cie_info *info)
{
/* We have to skip a pointer. Unfortunately, we don't know how
large it is. We find out by looking for a matching fixup. */
+ fixS *fix = seg_info (now_seg)->frchainP->fix_root;
while (fix != NULL
&& (fix->fx_frag != f || fix->fx_where != offset))
fix = fix->fx_next;
@@ -205,10 +207,10 @@ get_cie_info (struct cie_info *info)
f = f->fr_next;
}
if (f == NULL)
- return 0;
+ return false;
}
else if (augmentation[0] != 'z')
- return 0;
+ return false;
/* We're now at the code alignment factor, which is a ULEB128. If
it isn't a single byte, forget it. */
@@ -220,7 +222,7 @@ get_cie_info (struct cie_info *info)
info->code_alignment = code_alignment;
info->z_augmentation = (augmentation[0] == 'z');
- return 1;
+ return true;
}
enum frame_state
@@ -240,7 +242,7 @@ struct frame_data
{
enum frame_state state;
- int cie_info_ok;
+ bool cie_info_ok;
struct cie_info cie_info;
symbolS *size_end_sym;
@@ -320,20 +322,27 @@ check_eh_frame (expressionS *exp, unsigned int *pnbytes)
{
d->state = state_saw_size;
d->size_end_sym = exp->X_add_symbol;
+ if (!d->cie_info.f)
+ d->cie_info.f = frag_now;
}
}
break;
case state_saw_size:
case state_saw_cie_offset:
- /* Assume whatever form it appears in, it appears atomically. */
- d->state = (enum frame_state) (d->state + 1);
+ if (!(*pnbytes == 4 || *pnbytes == 8))
+ /* Stop scanning if we don't see the expected FDE fields. */
+ d->state = state_error;
+ else
+ d->state = (enum frame_state) (d->state + 1);
break;
case state_saw_pc_begin:
/* Decide whether we should see an augmentation. */
- if (! d->cie_info_ok
- && ! (d->cie_info_ok = get_cie_info (&d->cie_info)))
+ if (!(*pnbytes == 4 || *pnbytes == 8))
+ d->state = state_error;
+ else if (!d->cie_info_ok
+ && !(d->cie_info_ok = get_cie_info (&d->cie_info)))
d->state = state_error;
else if (d->cie_info.z_augmentation)
{
@@ -347,7 +356,7 @@ check_eh_frame (expressionS *exp, unsigned int *pnbytes)
case state_seeing_aug_size:
/* Bytes == -1 means this comes from an leb128 directive. */
- if ((int)*pnbytes == -1 && exp->X_op == O_constant)
+ if ((int) *pnbytes == -1 && exp->X_op == O_constant)
{
d->aug_size = exp->X_add_number;
d->state = state_skipping_aug;
@@ -367,7 +376,7 @@ check_eh_frame (expressionS *exp, unsigned int *pnbytes)
break;
case state_skipping_aug:
- if ((int)*pnbytes < 0)
+ if ((int) *pnbytes < 0)
d->state = state_error;
else
{
diff --git a/gas/testsuite/gas/aarch64/gpc3.d b/gas/testsuite/gas/aarch64/gpc3.d
new file mode 100644
index 0000000..2535aef
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/gpc3.d
@@ -0,0 +1,11 @@
+#name: RME_GPC3 System register
+#as: -march=armv9.5-a
+#objdump: -dr
+
+.*: file format .*
+
+Disassembly of section \.text:
+
+0+ <.*>:
+[^:]*: d53e21a0 mrs x0, gpcbw_el3
+[^:]*: d51e21a0 msr gpcbw_el3, x0
diff --git a/gas/testsuite/gas/aarch64/gpc3.s b/gas/testsuite/gas/aarch64/gpc3.s
new file mode 100644
index 0000000..349cc08
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/gpc3.s
@@ -0,0 +1,7 @@
+/* RME Granule Protection Check 3 Extension. */
+
+ /* Read from system register. */
+ mrs x0, gpcbw_el3
+
+ /* Write to system register. */
+ msr gpcbw_el3, x0
diff --git a/gas/testsuite/gas/aarch64/occmo.d b/gas/testsuite/gas/aarch64/occmo.d
new file mode 100644
index 0000000..388d8f4
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/occmo.d
@@ -0,0 +1,18 @@
+#name: FEAT_OCCMO Test
+#as: -march=armv9.5-a+memtag
+#objdump: -dr
+
+.*: file format .*
+
+Disassembly of section .text:
+
+0+ <.*>:
+
+[^:]*: d50b7b00 dc cvaoc, x0
+[^:]*: d50b7b1e dc cvaoc, x30
+[^:]*: d50b7be0 dc cgdvaoc, x0
+[^:]*: d50b7bfe dc cgdvaoc, x30
+[^:]*: d50b7f00 dc civaoc, x0
+[^:]*: d50b7f1e dc civaoc, x30
+[^:]*: d50b7fe0 dc cigdvaoc, x0
+[^:]*: d50b7ffe dc cigdvaoc, x30
diff --git a/gas/testsuite/gas/aarch64/occmo.s b/gas/testsuite/gas/aarch64/occmo.s
new file mode 100644
index 0000000..92cfaf0
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/occmo.s
@@ -0,0 +1,8 @@
+ dc cvaoc, x0
+ dc cvaoc, x30
+ dc cgdvaoc, x0
+ dc cgdvaoc, x30
+ dc civaoc, x0
+ dc civaoc, x30
+ dc cigdvaoc, x0
+ dc cigdvaoc, x30
diff --git a/gdb/NEWS b/gdb/NEWS
index a82b7e3..e0313bb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -90,6 +90,18 @@ info sharedlibrary
command are now for the full memory range allocated to the shared
library.
+info threads [-gid] [-stopped] [-running] [ID]...
+ If no threads match the given ID(s) or filter options, GDB now prints
+
+ No threads matched.
+
+ without printing the provided arguments. The newly added '-stopped'
+ option makes GDB list the stopped threads only. Similarly,
+ '-running' makes GDB list the running threads only. If both options
+ are given together, both stopped and running threads are listed.
+ These new flags can be useful to get a reduced list when there is a
+ large number of threads.
+
* GDB-internal Thread Local Storage (TLS) support
** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv
@@ -128,6 +140,14 @@ info sharedlibrary
when output is going to standard output, and False when output is
going to a string.
+ ** Setting the documentation string (__doc__) of a gdb.Parameter
+ sub-class to the empty string, means GDB will only display the
+ set_doc or show_doc strings in the set/show help output.
+
+ ** New gdb.ParameterPrefix class. This can be used to create 'set'
+ and 'show' gdb.Command prefixes, suitable for use with new
+ gdb.Parameters.
+
* Guile API
** New type <gdb:color> for dealing with colors.
@@ -135,6 +155,11 @@ info sharedlibrary
** New constant PARAM_COLOR represents color type of a value
of a <gdb:parameter> object. Parameter's value is <gdb::color> instance.
+ ** Eliding the #:doc string from make-parameter now means that GDB
+ will use a default documentation string. Setting #:doc to the
+ empty string for make-parameter means GDB will only display the
+ #:set_doc or #:show_doc strings in the set/show help output.
+
* New remote packets
binary-upload in qSupported reply
diff --git a/gdb/break-cond-parse.c b/gdb/break-cond-parse.c
index 705f4f6..caf13a7 100644
--- a/gdb/break-cond-parse.c
+++ b/gdb/break-cond-parse.c
@@ -569,10 +569,10 @@ test (const char *input, const char *condition, int thread = -1,
gdb::unique_xmalloc_ptr<char> extracted_rest;
int extracted_thread, extracted_inferior, extracted_task;
bool extracted_force_condition;
- std::string exception_msg, error_str;
+ std::string exception_msg;
- if (error_msg != nullptr)
- error_str = std::string (error_msg) + "\n";
+ if (error_msg == nullptr)
+ error_msg = "";
try
{
@@ -584,10 +584,7 @@ test (const char *input, const char *condition, int thread = -1,
}
catch (const gdb_exception_error &ex)
{
- string_file buf;
-
- exception_print (&buf, ex);
- exception_msg = buf.release ();
+ exception_msg = ex.what ();
}
if ((condition == nullptr) != (extracted_condition.get () == nullptr)
@@ -599,7 +596,7 @@ test (const char *input, const char *condition, int thread = -1,
|| inferior != extracted_inferior
|| task != extracted_task
|| force != extracted_force_condition
- || exception_msg != error_str)
+ || exception_msg != error_msg)
{
if (run_verbose ())
{
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index f53a138..bdf7674 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -3042,10 +3042,6 @@ classify_name (struct parser_state *par_state, const struct block *block,
std::string copy = copy_name (yylval.sval);
- /* Initialize this in case we *don't* use it in this call; that way
- we can refer to it unconditionally below. */
- memset (&is_a_field_of_this, 0, sizeof (is_a_field_of_this));
-
bsym = lookup_symbol (copy.c_str (), block, SEARCH_VFT,
par_state->language ()->name_of_this ()
? &is_a_field_of_this : NULL);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5e5e888..05f5502 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3807,7 +3807,7 @@ Thread 1 "main" received signal SIGINT, Interrupt.
@table @code
@anchor{info_threads}
@kindex info threads
-@item info threads @r{[}-gid@r{]} @r{[}@var{thread-id-list}@r{]}
+@item info threads @r{[}-gid@r{]} @r{[}-stopped@r{]} @r{[}-running@r{]} @r{[}@var{thread-id-list}@r{]}
Display information about one or more threads. With no arguments
displays information about all threads. You can specify the list of
@@ -3857,6 +3857,14 @@ If you're debugging multiple inferiors, @value{GDBN} displays thread
IDs using the qualified @var{inferior-num}.@var{thread-num} format.
Otherwise, only @var{thread-num} is shown.
+If you specify the @samp{-stopped} option, @value{GDBN} filters the
+output of the command to print the stopped threads only. Similarly,
+if you specify the @samp{-running} option, @value{GDBN} filters the
+output to print the running threads only. These options can be
+helpful to reduce the output list if there is a large number of
+threads. If you specify both options, @value{GDBN} prints both
+stopped and running threads.
+
If you specify the @samp{-gid} option, @value{GDBN} displays a column
indicating each thread's global thread ID:
diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index c6d889f..7b3f0a9 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -2098,8 +2098,10 @@ is the @code{<gdb:parameter>} object representing the parameter, and
This function must return a string, and will be displayed to the user.
@value{GDBN} will add a trailing newline.
-The argument @var{doc} is the help text for the new parameter.
-If there is no documentation string, a default value is used.
+The argument @var{doc} is the help text for the new parameter. If
+there is no documentation string, a default value is used. If the
+documentation string is empty, then @value{GDBN} will print just the
+@var{set-doc} and @var{show-doc} strings (see below).
The argument @var{set-doc} is the help text for this parameter's
@code{set} command.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 7bb6503..7f801ab 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -4558,6 +4558,7 @@ documentation string is provided, the default value @samp{This command
is not documented.} is used.
@end defun
+@anchor{Command.dont_repeat}
@cindex don't repeat Python command
@defun Command.dont_repeat ()
By default, a @value{GDBN} command is repeated when the user enters a
@@ -4568,6 +4569,7 @@ exception). This is similar to the user command @code{dont-repeat},
see @ref{Define, dont-repeat}.
@end defun
+@anchor{Command.invoke}
@defun Command.invoke (argument, from_tty)
This method is called by @value{GDBN} when this command is invoked.
@@ -5079,7 +5081,9 @@ string from the parameter's class, if there is one. If there is no
documentation string, a default value is used. The documentation
string is included in the output of the parameters @code{help set} and
@code{help show} commands, and should be written taking this into
-account.
+account. If the documentation string for the parameter's class is the
+empty string then @value{GDBN} will only use @code{Parameter.set_doc}
+or @code{Parameter.show_doc} (see below) in the @kbd{help} output.
@end defun
@defvar Parameter.set_doc
@@ -5258,6 +5262,99 @@ constants provided when the parameter is created.
The value is @code{gdb.Color} instance.
@end table
+When creating multiple new parameters using @code{gdb.Parameter}, it
+is often desirable to create a prefix command that can be used to
+group related parameters together, for example, if you wished to add
+the parameters @kbd{plugin-name feature-1} and @kbd{plugin-name
+feature-2}, then the @kbd{plugin-name} would need to be a prefix
+command (@pxref{CLI Commands In Python}).
+
+However, when creating parameters, you will almost always need to
+create two prefix commands, one as a @kbd{set} sub-command, and one as
+a @kbd{show} sub-command. @value{GDBN} provides the
+@code{gdb.ParameterPrefix} helper class to make creation of these two
+prefixes easier.
+
+@defun ParameterPrefix.__init__ (name, command_class, doc = @code{None})
+The object initializer for @code{ParameterPrefix} registers two new
+@code{gdb.Command} prefixes, one as a @kbd{set} sub-command, and the
+other as a @kbd{show} sub-command.
+
+@var{name}, a string, is the name of the new prefix, without either
+@kbd{set} or @kbd{show}, similar to the @var{name} passed to
+@code{gdb.Parameter} (@pxref{Parameters In Python}). For example, to
+create the prefixes @kbd{set plugin-name} and @kbd{show plugin-name},
+you would pass the string @kbd{plugin-name}.
+
+@var{command_class} should be one of the @samp{COMMAND_} constants
+(@pxref{CLI Commands In Python}). This argument tells @value{GDBN} how to
+categorize the new parameter prefixes in the help system.
+
+There are a number of ways in which the help text for the two new
+prefix commands can be provided. If the @var{doc} parameter is not
+@code{None}, then this will be used as the documentation string for
+both prefix commands.
+
+If @var{doc} is @code{None}, but @code{gdb.ParameterPrefix} has been
+sub-classed, then the prefix command documentation will be taken from
+sub-classes documentation string (i.e., the @code{__doc__} attribute).
+
+If @var{doc} is @code{None}, and there is no @code{__doc__} string,
+then the default value @samp{This command is not documented.} is used.
+
+When writing the help text, keep in mind that the same text is used
+for both the @kbd{set} and @kbd{show} prefix commands.
+@end defun
+
+@defun ParameterPrefix.invoke_set (argument, from_tty)
+If a sub-class defines this method, then @value{GDBN} will call this
+when the prefix command is used with an unknown sub-command. The
+@var{argument} and @var{from_tty} parameters are the same as for
+@code{gdb.Command.invoke} (@pxref{Command.invoke}).
+
+If this method throws an exception, it is turned into a @value{GDBN}
+@code{error} call. Otherwise, the return value is ignored.
+
+It is not required that a @code{ParameterPrefix} sub-class override
+this method. Usually, a parameter prefix only exists as a means to
+group related parameters together. @value{GDBN} handles this use case
+automatically with no need to implement @code{invoke_set}.
+@end defun
+
+@defun ParameterPrefix.invoke_show (argument, from_tty)
+This is like the @code{invoke_set} method, but for the @kbd{show}
+prefix command. As with @code{invoke_set}, implementation of this
+method is optional, and usually not required.
+@end defun
+
+@cindex don't repeat Python command
+@defun ParameterPrefix.dont_repeat ()
+Like @code{Command.dont_repeat} (@pxref{Command.dont_repeat}), this
+can be called from @code{ParameterPrefix.invoke_set} or
+@code{ParameterPrefix.invoke_show} to prevent the prefix commands from
+being repeated.
+@end defun
+
+Here is a small example that uses @code{gdb.ParameterPrefix} along
+with @code{gdb.Parameter} to create two new parameters
+@kbd{plugin-name feature-1} and @kbd{plugin-name feature-2}. As
+neither @code{invoke_set} or @code{invoke_show} is needed, this
+example does not sub-class @code{gdb.ParameterPrefix}:
+
+@smallexample
+class ExampleParam(gdb.Parameter):
+ def __init__ (self, name):
+ super ().__init__ (name, gdb.COMMAND_DATA, gdb.PARAM_BOOLEAN)
+ self.value = True
+
+gdb.ParameterPrefix("plugin-name", gdb.COMMAND_NONE,
+ """An example parameter prefix.
+
+ This groups together some parameters.""")
+ExampleParam("plugin-name feature-1")
+ExampleParam("plugin-name feature-2")
+@end smallexample
+
@node Functions In Python
@subsubsection Writing new convenience functions
diff --git a/gdb/dwarf2/dwz.c b/gdb/dwarf2/dwz.c
index 583103b..59fe8e4 100644
--- a/gdb/dwarf2/dwz.c
+++ b/gdb/dwarf2/dwz.c
@@ -56,35 +56,37 @@ dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
/* A helper function to find the sections for a .dwz file. */
static void
-locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp,
- dwz_file *dwz_file)
+locate_dwz_sections (objfile *objfile, dwz_file &dwz_file)
{
- dwarf2_section_info *sect = nullptr;
+ for (asection *sec : gdb_bfd_sections (dwz_file.dwz_bfd))
+ {
+ dwarf2_section_info *sect = nullptr;
- /* Note that we only support the standard ELF names, because .dwz
+ /* Note that we only support the standard ELF names, because .dwz
is ELF-only (at the time of writing). */
- if (dwarf2_elf_names.abbrev.matches (sectp->name))
- sect = &dwz_file->abbrev;
- else if (dwarf2_elf_names.info.matches (sectp->name))
- sect = &dwz_file->info;
- else if (dwarf2_elf_names.str.matches (sectp->name))
- sect = &dwz_file->str;
- else if (dwarf2_elf_names.line.matches (sectp->name))
- sect = &dwz_file->line;
- else if (dwarf2_elf_names.macro.matches (sectp->name))
- sect = &dwz_file->macro;
- else if (dwarf2_elf_names.gdb_index.matches (sectp->name))
- sect = &dwz_file->gdb_index;
- else if (dwarf2_elf_names.debug_names.matches (sectp->name))
- sect = &dwz_file->debug_names;
- else if (dwarf2_elf_names.types.matches (sectp->name))
- sect = &dwz_file->types;
-
- if (sect != nullptr)
- {
- sect->s.section = sectp;
- sect->size = bfd_section_size (sectp);
- sect->read (objfile);
+ if (dwarf2_elf_names.abbrev.matches (sec->name))
+ sect = &dwz_file.abbrev;
+ else if (dwarf2_elf_names.info.matches (sec->name))
+ sect = &dwz_file.info;
+ else if (dwarf2_elf_names.str.matches (sec->name))
+ sect = &dwz_file.str;
+ else if (dwarf2_elf_names.line.matches (sec->name))
+ sect = &dwz_file.line;
+ else if (dwarf2_elf_names.macro.matches (sec->name))
+ sect = &dwz_file.macro;
+ else if (dwarf2_elf_names.gdb_index.matches (sec->name))
+ sect = &dwz_file.gdb_index;
+ else if (dwarf2_elf_names.debug_names.matches (sec->name))
+ sect = &dwz_file.debug_names;
+ else if (dwarf2_elf_names.types.matches (sec->name))
+ sect = &dwz_file.types;
+
+ if (sect != nullptr)
+ {
+ sect->s.section = sec;
+ sect->size = bfd_section_size (sec);
+ sect->read (objfile);
+ }
}
}
@@ -392,9 +394,7 @@ dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile)
dwz_file_up result (new dwz_file (std::move (dwz_bfd)));
- for (asection *sec : gdb_bfd_sections (result->dwz_bfd))
- locate_dwz_sections (per_objfile->objfile, result->dwz_bfd.get (),
- sec, result.get ());
+ locate_dwz_sections (per_objfile->objfile, *result);
gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ());
bfd_cache_close (result->dwz_bfd.get ());
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 71fa793..891e10f 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -7512,45 +7512,66 @@ cutu_reader::open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name,
size of each of the DWO debugging sections we are interested in. */
void
-cutu_reader::locate_dwo_sections (struct objfile *objfile, bfd *abfd,
- asection *sectp, dwo_sections *dwo_sections)
+cutu_reader::locate_dwo_sections (objfile *objfile, dwo_file &dwo_file)
{
const struct dwop_section_names *names = &dwop_section_names;
+ dwo_sections &dwo_sections = dwo_file.sections;
+ bool complained_about_macro_already = false;
+
+ for (asection *sec : gdb_bfd_sections (dwo_file.dbfd))
+ {
+ struct dwarf2_section_info *dw_sect = nullptr;
+
+ if (names->abbrev_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.abbrev;
+ else if (names->info_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.infos.emplace_back (dwarf2_section_info {});
+ else if (names->line_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.line;
+ else if (names->loc_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.loc;
+ else if (names->loclists_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.loclists;
+ else if (names->macinfo_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.macinfo;
+ else if (names->macro_dwo.matches (sec->name))
+ {
+ /* gcc versions <= 13 generate multiple .debug_macro.dwo sections with
+ some unresolved links between them. It's not usable, so do as if
+ there were not there. */
+ if (!complained_about_macro_already)
+ {
+ if (dwo_sections.macro.s.section == nullptr)
+ dw_sect = &dwo_sections.macro;
+ else
+ {
+ warning (_("Multiple .debug_macro.dwo sections found in "
+ "%s, ignoring them."), dwo_file.dbfd->filename);
- struct dwarf2_section_info *dw_sect = nullptr;
-
- if (names->abbrev_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->abbrev;
- else if (names->info_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->infos.emplace_back (dwarf2_section_info {});
- else if (names->line_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->line;
- else if (names->loc_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->loc;
- else if (names->loclists_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->loclists;
- else if (names->macinfo_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->macinfo;
- else if (names->macro_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->macro;
- else if (names->rnglists_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->rnglists;
- else if (names->str_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->str;
- else if (names->str_offsets_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->str_offsets;
- else if (names->types_dwo.matches (sectp->name))
- dw_sect = &dwo_sections->types.emplace_back (dwarf2_section_info {});
-
- if (dw_sect != nullptr)
- {
- /* Make sure we don't overwrite a section info that has been filled in
+ dwo_sections.macro = dwarf2_section_info {};
+ complained_about_macro_already = true;
+ }
+ }
+ }
+ else if (names->rnglists_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.rnglists;
+ else if (names->str_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.str;
+ else if (names->str_offsets_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.str_offsets;
+ else if (names->types_dwo.matches (sec->name))
+ dw_sect = &dwo_sections.types.emplace_back (dwarf2_section_info {});
+
+ if (dw_sect != nullptr)
+ {
+ /* Make sure we don't overwrite a section info that has been filled in
already. */
- gdb_assert (!dw_sect->readin);
+ gdb_assert (!dw_sect->readin);
- dw_sect->s.section = sectp;
- dw_sect->size = bfd_section_size (sectp);
- dw_sect->read (objfile);
+ dw_sect->s.section = sec;
+ dw_sect->size = bfd_section_size (sec);
+ dw_sect->read (objfile);
+ }
}
}
@@ -7578,9 +7599,7 @@ cutu_reader::open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name,
dwo_file->comp_dir = comp_dir;
dwo_file->dbfd = std::move (dbfd);
- for (asection *sec : gdb_bfd_sections (dwo_file->dbfd))
- this->locate_dwo_sections (per_objfile->objfile, dwo_file->dbfd.get (), sec,
- &dwo_file->sections);
+ this->locate_dwo_sections (per_objfile->objfile, *dwo_file);
/* There is normally just one .debug_info.dwo section in a DWO file. But when
building with -fdebug-types-section, gcc produces multiple .debug_info.dwo
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 5b4c8f6..aaac5e7 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -1029,8 +1029,7 @@ private:
dwo_file_up open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name,
const char *comp_dir);
- void locate_dwo_sections (struct objfile *objfile, bfd *abfd, asection *sectp,
- struct dwo_sections *dwo_sections);
+ void locate_dwo_sections (objfile *objfile, dwo_file &dwo_file);
void create_dwo_unit_hash_tables (dwo_file &dwo_file, dwarf2_cu &skeleton_cu,
dwarf2_section_info &section,
diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c
index 4757872..453394c 100644
--- a/gdb/guile/scm-cmd.c
+++ b/gdb/guile/scm-cmd.c
@@ -509,7 +509,7 @@ gdbscm_parse_command_name (const char *name,
const char *prefix_text2 = prefix_text.get ();
elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
- if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
+ if (elt == nullptr || elt == CMD_LIST_AMBIGUOUS || *prefix_text2 != '\0')
{
msg = xstrprintf (_("could not find command prefix '%s'"),
prefix_text.get ()).release ();
diff --git a/gdb/guile/scm-param.c b/gdb/guile/scm-param.c
index 65226ec..5137847 100644
--- a/gdb/guile/scm-param.c
+++ b/gdb/guile/scm-param.c
@@ -308,13 +308,37 @@ pascm_is_valid (param_smob *p_smob)
return p_smob->commands.set != nullptr;
}
-/* A helper function which return the default documentation string for
- a parameter (which is to say that it's undocumented). */
+
+/* The different types of documentation string. */
+
+enum doc_string_type
+{
+ doc_string_set,
+ doc_string_show,
+ doc_string_description
+};
+
+/* A helper function which returns the default documentation string for
+ a parameter CMD_NAME. The DOC_TYPE indicates which type of
+ documentation string is needed. The returned string is dynamically
+ allocated. */
static char *
-get_doc_string (void)
+get_doc_string (doc_string_type doc_type, const char *cmd_name)
{
- return xstrdup (_("This command is not documented."));
+ if (doc_type == doc_string_description)
+ return xstrdup (_("This command is not documented."));
+ else
+ {
+ gdb_assert (cmd_name != nullptr);
+
+ if (doc_type == doc_string_show)
+ return xstrprintf (_("Show the current value of '%s'."),
+ cmd_name).release ();
+ else
+ return xstrprintf (_("Set the current value of '%s'."),
+ cmd_name).release ();
+ }
}
/* Subroutine of pascm_set_func, pascm_show_func to simplify them.
@@ -990,11 +1014,14 @@ gdbscm_make_parameter (SCM name_scm, SCM rest)
&show_doc_arg_pos, &show_doc,
&initial_value_arg_pos, &initial_value_scm);
- /* If doc is NULL, leave it NULL. See add_setshow_cmd_full. */
+ if (doc == nullptr)
+ doc = get_doc_string (doc_string_description, nullptr);
+ else if (*doc == '\0')
+ doc = nullptr;
if (set_doc == NULL)
- set_doc = get_doc_string ();
+ set_doc = get_doc_string (doc_string_set, name);
if (show_doc == NULL)
- show_doc = get_doc_string ();
+ show_doc = get_doc_string (doc_string_show, name);
s = name;
name = gdbscm_canonicalize_command_name (s, 0);
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index bbffb3d..0b08e12 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -630,9 +630,9 @@ mapping_is_anonymous_p (const char *filename)
return 0;
}
-/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
- MAYBE_PRIVATE_P, MAPPING_ANONYMOUS_P, ADDR and OFFSET) should not
- be dumped, or greater than 0 if it should.
+/* Return false if the memory mapping represented by MAP should not be
+ dumped, or true if it should. FILTERFLAGS guides which mappings
+ should be dumped.
In a nutshell, this is the logic that we follow in order to decide
if a mapping should be dumped or not.
@@ -677,11 +677,14 @@ mapping_is_anonymous_p (const char *filename)
header (of a DSO or an executable, for example). If it is, and
if the user is interested in dump it, then we should dump it. */
-static int
-dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
- int maybe_private_p, int mapping_anon_p, int mapping_file_p,
- const char *filename, ULONGEST addr, ULONGEST offset)
+static bool
+dump_mapping_p (filter_flags filterflags, const smaps_data &map)
{
+ /* Older Linux kernels did not support the "Anonymous:" counter.
+ If it is missing, we can't be sure what to dump, so dump everything. */
+ if (!map.has_anonymous)
+ return true;
+
/* Initially, we trust in what we received from our caller. This
value may not be very precise (i.e., it was probably gathered
from the permission line in the /proc/PID/smaps list, which
@@ -689,41 +692,42 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
what we have until we take a look at the "VmFlags:" field
(assuming that the version of the Linux kernel being used
supports it, of course). */
- int private_p = maybe_private_p;
- int dump_p;
+ int private_p = map.priv;
/* We always dump vDSO and vsyscall mappings, because it's likely that
there'll be no file to read the contents from at core load time.
The kernel does the same. */
- if (strcmp ("[vdso]", filename) == 0
- || strcmp ("[vsyscall]", filename) == 0)
- return 1;
+ if (map.filename == "[vdso]" || map.filename == "[vsyscall]")
+ return true;
- if (v->initialized_p)
+ if (map.vmflags.initialized_p)
{
/* We never dump I/O mappings. */
- if (v->io_page)
- return 0;
+ if (map.vmflags.io_page)
+ return false;
/* Check if we should exclude this mapping. */
- if (!dump_excluded_mappings && v->exclude_coredump)
- return 0;
+ if (!dump_excluded_mappings && map.vmflags.exclude_coredump)
+ return false;
/* Update our notion of whether this mapping is shared or
private based on a trustworthy value. */
- private_p = !v->shared_mapping;
+ private_p = !map.vmflags.shared_mapping;
/* HugeTLB checking. */
- if (v->uses_huge_tlb)
+ if (map.vmflags.uses_huge_tlb)
{
if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
|| (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
- return 1;
+ return true;
- return 0;
+ return false;
}
}
+ int mapping_anon_p = map.mapping_anon_p;
+ int mapping_file_p = map.mapping_file_p;
+ bool dump_p;
if (private_p)
{
if (mapping_anon_p && mapping_file_p)
@@ -763,7 +767,7 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
A mapping contains an ELF header if it is a private mapping, its
offset is zero, and its first word is ELFMAG. */
- if (!dump_p && private_p && offset == 0
+ if (!dump_p && private_p && map.offset == 0
&& (filterflags & COREFILTER_ELF_HEADERS) != 0)
{
/* Useful define specifying the size of the ELF magical
@@ -774,7 +778,7 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
/* Let's check if we have an ELF header. */
gdb_byte h[SELFMAG];
- if (target_read_memory (addr, h, SELFMAG) == 0)
+ if (target_read_memory (map.start_address, h, SELFMAG) == 0)
{
/* The EI_MAG* and ELFMAG* constants come from
<elf/common.h>. */
@@ -783,7 +787,7 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
{
/* This mapping contains an ELF header, so we
should dump it. */
- dump_p = 1;
+ dump_p = true;
}
}
}
@@ -794,20 +798,25 @@ dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
/* As above, but return true only when we should dump the NT_FILE
entry. */
-static int
-dump_note_entry_p (filter_flags filterflags, const struct smaps_vmflags *v,
- int maybe_private_p, int mapping_anon_p, int mapping_file_p,
- const char *filename, ULONGEST addr, ULONGEST offset)
+static bool
+dump_note_entry_p (filter_flags filterflags, const smaps_data &map)
{
+ /* No NT_FILE entry for mappings with no filename. */
+ if (map.filename.length () == 0)
+ return false;
+
+ /* Don't add NT_FILE entries for mappings with a zero inode. */
+ if (map.inode == 0)
+ return false;
+
/* vDSO and vsyscall mappings will end up in the core file. Don't
put them in the NT_FILE note. */
- if (strcmp ("[vdso]", filename) == 0
- || strcmp ("[vsyscall]", filename) == 0)
- return 0;
+ if (map.filename == "[vdso]" || map.filename == "[vsyscall]")
+ return false;
/* Otherwise, any other file-based mapping should be placed in the
note. */
- return 1;
+ return true;
}
/* Implement the "info proc" command. */
@@ -1314,21 +1323,15 @@ linux_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
}
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
- ULONGEST offset, ULONGEST inode,
+ ULONGEST offset,
int read, int write,
int exec, int modified,
bool memory_tagged,
- const char *filename,
+ const std::string &filename,
void *data);
-typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
- const struct smaps_vmflags *v,
- int maybe_private_p,
- int mapping_anon_p,
- int mapping_file_p,
- const char *filename,
- ULONGEST addr,
- ULONGEST offset);
+typedef bool linux_dump_mapping_p_ftype (filter_flags filterflags,
+ const smaps_data &map);
/* Helper function to parse the contents of /proc/<pid>/smaps into a data
structure, for easy access.
@@ -1590,35 +1593,15 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
for (const struct smaps_data &map : smaps)
{
- int should_dump_p = 0;
-
- if (map.has_anonymous)
- {
- should_dump_p
- = should_dump_mapping_p (filterflags, &map.vmflags,
- map.priv,
- map.mapping_anon_p,
- map.mapping_file_p,
- map.filename.c_str (),
- map.start_address,
- map.offset);
- }
- else
- {
- /* Older Linux kernels did not support the "Anonymous:" counter.
- If it is missing, we can't be sure - dump all the pages. */
- should_dump_p = 1;
- }
-
/* Invoke the callback function to create the corefile segment. */
- if (should_dump_p)
+ if (should_dump_mapping_p (filterflags, map))
{
func (map.start_address, map.end_address - map.start_address,
- map.offset, map.inode, map.read, map.write, map.exec,
+ map.offset, map.read, map.write, map.exec,
1, /* MODIFIED is true because we want to dump
the mapping. */
map.vmflags.memory_tagging != 0,
- map.filename.c_str (), obfd);
+ map.filename, obfd);
}
}
@@ -1644,10 +1627,10 @@ struct linux_find_memory_regions_data
static int
linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
- ULONGEST offset, ULONGEST inode,
+ ULONGEST offset,
int read, int write, int exec, int modified,
bool memory_tagged,
- const char *filename, void *arg)
+ const std::string &filename, void *arg)
{
struct linux_find_memory_regions_data *data
= (struct linux_find_memory_regions_data *) arg;
@@ -1693,8 +1676,6 @@ struct linux_make_mappings_data
struct type *long_type;
};
-static linux_find_memory_region_ftype linux_make_mappings_callback;
-
/* A callback for linux_find_memory_regions_full that updates the
mappings data for linux_make_mappings_corefile_notes.
@@ -1703,17 +1684,16 @@ static linux_find_memory_region_ftype linux_make_mappings_callback;
static int
linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
- ULONGEST offset, ULONGEST inode,
+ ULONGEST offset,
int read, int write, int exec, int modified,
bool memory_tagged,
- const char *filename, void *data)
+ const std::string &filename, void *data)
{
struct linux_make_mappings_data *map_data
= (struct linux_make_mappings_data *) data;
gdb_byte buf[sizeof (ULONGEST)];
- if (*filename == '\0' || inode == 0)
- return 0;
+ gdb_assert (filename.length () > 0);
++map_data->file_count;
@@ -1724,7 +1704,7 @@ linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
pack_long (buf, map_data->long_type, offset);
obstack_grow (map_data->data_obstack, buf, map_data->long_type->length ());
- obstack_grow_str0 (map_data->filename_obstack, filename);
+ obstack_grow_str0 (map_data->filename_obstack, filename.c_str ());
return 0;
}
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index 092127dd..d79ec68 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -74,7 +74,9 @@ loongarch_insn_is_cond_branch (insn_t insn)
|| (insn & 0xfc000000) == 0x68000000 /* bltu */
|| (insn & 0xfc000000) == 0x6c000000 /* bgeu */
|| (insn & 0xfc000000) == 0x40000000 /* beqz */
- || (insn & 0xfc000000) == 0x44000000) /* bnez */
+ || (insn & 0xfc000000) == 0x44000000 /* bnez */
+ || (insn & 0xfc000300) == 0x48000000 /* bceqz */
+ || (insn & 0xfc000300) == 0x48000100) /* bcnez */
return true;
return false;
}
@@ -314,6 +316,20 @@ loongarch_next_pc (struct regcache *regcache, CORE_ADDR cur_pc)
if (rj != 0)
next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1);
}
+ else if ((insn & 0xfc000300) == 0x48000000) /* bceqz cj, offs21 */
+ {
+ LONGEST cj = regcache_raw_get_signed (regcache,
+ loongarch_decode_imm ("5:3", insn, 0) + LOONGARCH_FIRST_FCC_REGNUM);
+ if (cj == 0)
+ next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1);
+ }
+ else if ((insn & 0xfc000300) == 0x48000100) /* bcnez cj, offs21 */
+ {
+ LONGEST cj = regcache_raw_get_signed (regcache,
+ loongarch_decode_imm ("5:3", insn, 0) + LOONGARCH_FIRST_FCC_REGNUM);
+ if (cj != 0)
+ next_pc = cur_pc + loongarch_decode_imm ("0:5|10:16<<2", insn, 1);
+ }
else if ((insn & 0xffff8000) == 0x002b0000) /* syscall */
{
if (tdep->syscall_next_pc != nullptr)
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 4ea5d06..69c15b1 100644
--- a/gdb/python/lib/gdb/__init__.py
+++ b/gdb/python/lib/gdb/__init__.py
@@ -392,3 +392,121 @@ def _handle_missing_objfile(pspace, buildid, filename):
return _handle_missing_files(
pspace, "objfile", lambda h: h(pspace, buildid, filename)
)
+
+
+class ParameterPrefix:
+ # A wrapper around gdb.Command for creating set/show prefixes.
+ #
+ # When creating a gdb.Parameter sub-classes, it is sometimes necessary
+ # to first create a gdb.Command object in order to create the needed
+ # command prefix. However, for parameters, we actually need two
+ # prefixes, a 'set' prefix, and a 'show' prefix. With this helper
+ # class, a single instance of this class will create both prefixes at
+ # once.
+ #
+ # It is important that this class-level documentation not be a __doc__
+ # string. Users are expected to sub-class this ParameterPrefix class
+ # and add their own documentation. If they don't, then GDB will
+ # generate a suitable doc string. But, if this (parent) class has a
+ # __doc__ string of its own, then sub-classes will inherit that __doc__
+ # string, and GDB will not understand that it needs to generate one.
+
+ class _PrefixCommand(_gdb.Command):
+ """A gdb.Command used to implement both the set and show prefixes.
+
+ This documentation string is not used as the prefix command
+ documentation as it is overridden in the __init__ method below."""
+
+ # This private method is connected to the 'invoke' attribute within
+ # this _PrefixCommand object if the containing ParameterPrefix
+ # object has an invoke_set or invoke_show method.
+ #
+ # This method records within self.__delegate which _PrefixCommand
+ # object is currently active, and then calls the correct invoke
+ # method on the delegat object (the ParameterPrefix sub-class
+ # object).
+ #
+ # Recording the currently active _PrefixCommand object is important;
+ # if from the invoke method the user calls dont_repeat, then this is
+ # forwarded to the currently active _PrefixCommand object.
+ def __invoke(self, args, from_tty):
+
+ # A helper class for use as part of a Python 'with' block.
+ # Records which gdb.Command object is currently running its
+ # invoke method.
+ class MarkActiveCallback:
+ # The CMD is a _PrefixCommand object, and the DELEGATE is
+ # the ParameterPrefix class, or sub-class object. At this
+ # point we simple record both of these within the
+ # MarkActiveCallback object.
+ def __init__(self, cmd, delegate):
+ self.__cmd = cmd
+ self.__delegate = delegate
+
+ # Record the currently active _PrefixCommand object within
+ # the outer ParameterPrefix sub-class object.
+ def __enter__(self):
+ self.__delegate.active_prefix = self.__cmd
+
+ # Once the invoke method has completed, then clear the
+ # _PrefixCommand object that was stored into the outer
+ # ParameterPrefix sub-class object.
+ def __exit__(self, exception_type, exception_value, traceback):
+ self.__delegate.active_prefix = None
+
+ # The self.__cb attribute is set when the _PrefixCommand object
+ # is created, and is either invoke_set or invoke_show within the
+ # ParameterPrefix sub-class object.
+ assert callable(self.__cb)
+
+ # Record the currently active _PrefixCommand object within the
+ # ParameterPrefix sub-class object, then call the relevant
+ # invoke method within the ParameterPrefix sub-class object.
+ with MarkActiveCallback(self, self.__delegate):
+ self.__cb(args, from_tty)
+
+ @staticmethod
+ def __find_callback(delegate, mode):
+ """The MODE is either 'set' or 'show'. Look for an invoke_MODE method
+ on DELEGATE, if a suitable method is found, then return it, otherwise,
+ return None.
+ """
+ cb = getattr(delegate, "invoke_" + mode, None)
+ if callable(cb):
+ return cb
+ return None
+
+ def __init__(self, mode, name, cmd_class, delegate, doc=None):
+ """Setup this gdb.Command. Mode is a string, either 'set' or 'show'.
+ NAME is the name for this prefix command, that is, the
+ words that appear after both 'set' and 'show' in the
+ command name. CMD_CLASS is the usual enum. And DELEGATE
+ is the gdb.ParameterPrefix object this prefix is part of.
+ """
+ assert mode == "set" or mode == "show"
+ if doc is None:
+ self.__doc__ = delegate.__doc__
+ else:
+ self.__doc__ = doc
+ self.__cb = self.__find_callback(delegate, mode)
+ self.__delegate = delegate
+ if self.__cb is not None:
+ self.invoke = self.__invoke
+ super().__init__(mode + " " + name, cmd_class, prefix=True)
+
+ def __init__(self, name, cmd_class, doc=None):
+ """Create a _PrefixCommand for both the set and show prefix commands.
+ NAME is the command name without either the leading 'set ' or
+ 'show ' strings, and CMD_CLASS is the usual enum value.
+ """
+ self.active_prefix = None
+ self._set_prefix_cmd = self._PrefixCommand("set", name, cmd_class, self, doc)
+ self._show_prefix_cmd = self._PrefixCommand("show", name, cmd_class, self, doc)
+
+ # When called from within an invoke method the self.active_prefix
+ # attribute should be set to a gdb.Command sub-class (a _PrefixCommand
+ # object, see above). Forward the dont_repeat call to this object to
+ # register the actual command as none repeating.
+ def dont_repeat(self):
+ if self.active_prefix is not None:
+ self.active_prefix.dont_repeat()
diff --git a/gdb/python/lib/gdb/dap/sources.py b/gdb/python/lib/gdb/dap/sources.py
index 625c01f..efcd799 100644
--- a/gdb/python/lib/gdb/dap/sources.py
+++ b/gdb/python/lib/gdb/dap/sources.py
@@ -64,9 +64,9 @@ def decode_source(source):
"""Decode a Source object.
Finds and returns the filename of a given Source object."""
- if "path" in source:
- return source["path"]
- if "sourceReference" not in source:
+ if "sourceReference" not in source or source["sourceReference"] <= 0:
+ if "path" in source:
+ return source["path"]
raise DAPException("either 'path' or 'sourceReference' must appear in Source")
ref = source["sourceReference"]
if ref not in _id_map:
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index 5d98d03..c53138a 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -385,7 +385,7 @@ gdbpy_parse_command_name (const char *name,
prefix_text2 = prefix_text.c_str ();
elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
- if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
+ if (elt == nullptr || elt == CMD_LIST_AMBIGUOUS || *prefix_text2 != '\0')
{
PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
prefix_text.c_str ());
diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c
index 763680e..06237b6 100644
--- a/gdb/python/py-param.c
+++ b/gdb/python/py-param.c
@@ -495,7 +495,11 @@ get_doc_string (PyObject *object, enum doc_string_type doc_type,
}
}
- if (result == nullptr)
+ /* For the set/show docs, if these strings are empty then we set then to
+ a non-empty string. This ensures that the command has some sane
+ documentation for its 'help' text. */
+ if (result == nullptr
+ || (doc_type != doc_string_description && *result == '\0'))
{
if (doc_type == doc_string_description)
result.reset (xstrdup (_("This command is not documented.")));
@@ -904,6 +908,18 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds)
show_doc = get_doc_string (self, doc_string_show, name);
doc = get_doc_string (self, doc_string_description, cmd_name.get ());
+ /* The set/show docs should always be a non-empty string. */
+ gdb_assert (set_doc != nullptr && *set_doc != '\0');
+ gdb_assert (show_doc != nullptr && *show_doc != '\0');
+
+ /* For the DOC string only, if it is the empty string, then we convert it
+ to NULL. This means GDB will not even display a blank line for this
+ part of the help text, instead the set/show line is all the user will
+ get. */
+ gdb_assert (doc != nullptr);
+ if (*doc == '\0')
+ doc = nullptr;
+
Py_INCREF (self);
try
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5147aee..313aa5f 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2163,13 +2163,6 @@ lookup_symbol_aux (const char *name, symbol_name_match_type match_type,
domain_name (domain).c_str (), language_str (language));
}
- /* Make sure we do something sensible with is_a_field_of_this, since
- the callers that set this parameter to some non-null value will
- certainly use it later. If we don't set it, the contents of
- is_a_field_of_this are undefined. */
- if (is_a_field_of_this != NULL)
- memset (is_a_field_of_this, 0, sizeof (*is_a_field_of_this));
-
langdef = language_def (language);
/* Search specified block and its superiors. Don't search
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e547d10..0a57be5 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2101,17 +2101,17 @@ struct field_of_this_result
symbol was not found in 'this'. If non-NULL, then one of the
other fields will be non-NULL as well. */
- struct type *type;
+ struct type *type = nullptr;
/* If the symbol was found as an ordinary field of 'this', then this
is non-NULL and points to the particular field. */
- struct field *field;
+ struct field *field = nullptr;
/* If the symbol was found as a function field of 'this', then this
is non-NULL and points to the particular field. */
- struct fn_fieldlist *fn_field;
+ struct fn_fieldlist *fn_field = nullptr;
};
/* Find the definition for a specified symbol name NAME
diff --git a/gdb/testsuite/gdb.base/foll-fork-syscall.c b/gdb/testsuite/gdb.base/foll-fork-syscall.c
new file mode 100644
index 0000000..ef695f5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/foll-fork-syscall.c
@@ -0,0 +1,35 @@
+/* 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 <unistd.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ int pid, x = 0;
+
+ pid = fork ();
+ if (pid == 0) /* set breakpoint here */
+ printf ("I am the child\n");
+ else
+ printf ("I am the parent\n");
+
+ chdir (".");
+ ++x; /* set exit breakpoint here */
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/foll-fork-syscall.exp b/gdb/testsuite/gdb.base/foll-fork-syscall.exp
new file mode 100644
index 0000000..4aee683
--- /dev/null
+++ b/gdb/testsuite/gdb.base/foll-fork-syscall.exp
@@ -0,0 +1,142 @@
+# Copyright 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test catching syscalls with all permutations of follow-fork parent/child
+# and detach-on-fork on/off.
+
+# Test relies on checking follow-fork output. Do not run if gdb debug is
+# enabled because it will be redirected to the log.
+require !gdb_debug_enabled
+require {is_any_target "i?86-*-*" "x86_64-*-*"}
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+ return -1
+}
+
+proc setup_gdb {} {
+ global testfile
+
+ clean_restart $testfile
+
+ if {![runto_main]} {
+ return false
+ }
+
+ # Set a breakpoint after the fork is "complete."
+ if {![gdb_breakpoint [gdb_get_line_number "set breakpoint here"]]} {
+ return false
+ }
+
+ # Set exit breakpoint (to prevent inferior from exiting).
+ if {![gdb_breakpoint [gdb_get_line_number "set exit breakpoint here"]]} {
+ return false
+ }
+ return true
+}
+
+# Check that fork catchpoints are supported, as an indicator for whether
+# fork-following is supported. Return 1 if they are, else 0.
+
+proc_with_prefix check_fork_catchpoints {} {
+ global gdb_prompt
+
+ if { ![setup_gdb] } {
+ return false
+ }
+
+ # Verify that the system supports "catch fork".
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "insert first fork catchpoint"
+ set has_fork_catchpoints false
+ gdb_test_multiple "continue" "continue to first fork catchpoint" {
+ -re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" {
+ unsupported "continue to first fork catchpoint"
+ }
+ -re ".*Catchpoint.*$gdb_prompt $" {
+ set has_fork_catchpoints true
+ pass "continue to first fork catchpoint"
+ }
+ }
+
+ return $has_fork_catchpoints
+}
+
+proc_with_prefix test_catch_syscall {follow-fork-mode detach-on-fork} {
+ # Start with shiny new gdb instance.
+ if {![setup_gdb]} {
+ return
+ }
+
+ # The "Detaching..." and "Attaching..." messages may be hidden by
+ # default.
+ gdb_test_no_output "set verbose"
+
+ # Setup modes to test.
+ gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}"
+ gdb_test_no_output "set detach-on-fork ${detach-on-fork}"
+
+ gdb_test "catch fork" "Catchpoint . \\(fork\\)"
+ gdb_test "catch syscall chdir" "Catchpoint . \\(syscall 'chdir'.*\\)"
+
+ # Which inferior we're expecting to follow. Assuming the parent
+ # will be inferior #1, and the child will be inferior #2.
+ if {${follow-fork-mode} == "parent"} {
+ set following_inf 1
+ } else {
+ set followin_inf 2
+ }
+ # Next stop should be the fork catchpoint.
+ set expected_re ""
+ append expected_re "Catchpoint . \\(forked process.*"
+ gdb_test "continue" $expected_re "continue to fork catchpoint"
+
+ # Next stop should be the breakpoint after the fork.
+ set expected_re ".*"
+ if {${follow-fork-mode} == "child" || ${detach-on-fork} == "off"} {
+ append expected_re "\\\[New inferior.*"
+ }
+ if {${detach-on-fork} == "on"} {
+ append expected_re "\\\[Detaching after fork from "
+ if {${follow-fork-mode} == "parent"} {
+ append expected_re "child"
+ } else {
+ append expected_re "parent"
+ }
+ append expected_re " process.*"
+ }
+ append expected_re "Breakpoint .*set breakpoint here.*"
+ gdb_test "continue" $expected_re "continue to breakpoint after fork"
+
+ # Next stop should be the syscall catchpoint.
+ set expected_re ".*Catchpoint . \\(call to syscall chdir\\).*"
+ gdb_test continue $expected_re "continue to chdir syscall"
+}
+
+# Check for follow-fork support.
+if {![check_fork_catchpoints]} {
+ untested "follow-fork not supported"
+ return
+}
+
+# Test all permutations.
+foreach_with_prefix follow-fork-mode {"parent" "child"} {
+
+ # Do not run tests when not detaching from the parent.
+ # See breakpoints/13457 for discussion.
+ foreach_with_prefix detach-on-fork {"on"} {
+ test_catch_syscall ${follow-fork-mode} ${detach-on-fork}
+ }
+}
diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp
index 7822e4a..a0947e2 100644
--- a/gdb/testsuite/gdb.base/options.exp
+++ b/gdb/testsuite/gdb.base/options.exp
@@ -508,12 +508,26 @@ proc_with_prefix test-thread-apply {} {
proc_with_prefix test-info-threads {} {
test_gdb_complete_multiple "info threads " "" "" {
"-gid"
+ "-running"
+ "-stopped"
"ID"
}
+ test_gdb_complete_multiple "info threads " "-" "" {
+ "-gid"
+ "-running"
+ "-stopped"
+ }
+
test_gdb_complete_unique \
- "info threads -" \
+ "info threads -g" \
"info threads -gid"
+ test_gdb_complete_unique \
+ "info threads -r" \
+ "info threads -running"
+ test_gdb_complete_unique \
+ "info threads -s" \
+ "info threads -stopped"
# "ID" isn't really something the user can type.
test_gdb_complete_none "info threads I"
diff --git a/gdb/testsuite/gdb.guile/scm-cmd.exp b/gdb/testsuite/gdb.guile/scm-cmd.exp
index 9caca24..3709cb1 100644
--- a/gdb/testsuite/gdb.guile/scm-cmd.exp
+++ b/gdb/testsuite/gdb.guile/scm-cmd.exp
@@ -71,6 +71,65 @@ gdb_test_multiline "input subcommand" \
gdb_test "prefix-cmd subcmd ugh" "subcmd output, arg = ugh" "call subcmd"
+# Create a sub-command using a partial, but still unique, prefix.
+
+gdb_test_multiline "sub-command using partial prefix" \
+ "guile" "" \
+ "(register-command! (make-command \"prefix subcmd2\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:invoke (lambda (self arg from-tty)" "" \
+ " (display (format #f \"subcmd2 output, arg = ~a\\n\" arg)))))" "" \
+ "end" ""
+
+gdb_test "prefix-cmd subcmd2 ugh" "subcmd2 output, arg = ugh" "call subcmd2"
+
+# Now create a second prefix, similar to the first.
+
+gdb_test_multiline "create prefix-xxx prefix command" \
+ "guile" "" \
+ "(register-command! (make-command \"prefix-xxx\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:completer-class COMPLETE_NONE" "" \
+ " #:prefix? #t))" "" \
+ "end" ""
+
+# Now create a sub-command using an ambiguous prefix.
+
+gdb_test_multiline "sub-command using ambiguous partial prefix" \
+ "guile" "" \
+ "(register-command! (make-command \"prefix subcmd3\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:invoke (lambda (self arg from-tty)" "" \
+ " (display (format #f \"subcmd3 output, arg = ~a\\n\" arg)))))" "" \
+ "end" \
+ [multi_line \
+ "Out of range: could not find command prefix 'prefix' in position 1: \"prefix subcmd3\"" \
+ "Error while executing Scheme code\\."]
+
+# Check for errors when creating a command with an unknown prefix.
+
+gdb_test_multiline "try to create 'unknown-prefix subcmd'" \
+ "guile" "" \
+ "(register-command! (make-command \"unknown-prefix subcmd\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:invoke (lambda (self arg from-tty)" "" \
+ " (display \"called unknown-prefix subcmd\"))))" "" \
+ "end" \
+ [multi_line \
+ "Out of range: could not find command prefix 'unknown-prefix' in position 1: \"unknown-prefix subcmd\"" \
+ "Error while executing Scheme code\\."]
+
+gdb_test_multiline "try to create 'prefix-cmd unknown-prefix subcmd'" \
+ "guile" "" \
+ "(register-command! (make-command \"prefix-cmd unknown-prefix subcmd\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:invoke (lambda (self arg from-tty)" "" \
+ " (display \"called prefix-cmd unknown-prefix subcmd\"))))" "" \
+ "end" \
+ [multi_line \
+ "Out of range: could not find command prefix 'prefix-cmd unknown-prefix' in position 1: \"prefix-cmd unknown-prefix subcmd\"" \
+ "Error while executing Scheme code\\."]
+
# Test a subcommand in an existing GDB prefix.
gdb_test_multiline "input new subcommand" \
diff --git a/gdb/testsuite/gdb.guile/scm-parameter.exp b/gdb/testsuite/gdb.guile/scm-parameter.exp
index 8ab5d93..06eebdd 100644
--- a/gdb/testsuite/gdb.guile/scm-parameter.exp
+++ b/gdb/testsuite/gdb.guile/scm-parameter.exp
@@ -67,9 +67,19 @@ with_test_prefix "test-param" {
gdb_test_no_output "set print test-param off"
gdb_test "show print test-param" "The state of the Test Parameter is off." "show parameter off"
gdb_test "guile (print (parameter-value test-param))" "= #f" "parameter value, false"
- gdb_test "help show print test-param" "Show the state of the boolean test-param.*" "show help"
- gdb_test "help set print test-param" "Set the state of the boolean test-param.*" "set help"
- gdb_test "help set print" "set print test-param -- Set the state of the boolean test-param.*" "general help"
+ gdb_test "help show print test-param" \
+ [multi_line \
+ "^Show the state of the boolean test-param\\." \
+ "When enabled, test param does something useful\\. When disabled, does nothing\\."] \
+ "show help"
+ gdb_test "help set print test-param" \
+ [multi_line \
+ "^Set the state of the boolean test-param\\." \
+ "When enabled, test param does something useful\\. When disabled, does nothing\\."] \
+ "set help"
+ gdb_test "help set print" \
+ "set print test-param -- Set the state of the boolean test-param.*" \
+ "general help"
gdb_test "guile (print (parameter? test-param))" "= #t"
gdb_test "guile (print (parameter? 42))" "= #f"
@@ -314,9 +324,17 @@ with_test_prefix "test-undocumented-param" {
gdb_test "show print test-undoc-param" "The state of the Test Parameter is on." "show parameter on"
gdb_test_no_output "set print test-undoc-param off"
gdb_test "show print test-undoc-param" "The state of the Test Parameter is off." "show parameter off"
- gdb_test "help show print test-undoc-param" "This command is not documented." "show help"
- gdb_test "help set print test-undoc-param" "This command is not documented." "set help"
- gdb_test "help set print" "set print test-undoc-param -- This command is not documented.*" "general help"
+ gdb_test "help show print test-undoc-param" \
+ [multi_line \
+ "^Show the current value of 'print test-undoc-param'\\." \
+ "This command is not documented\\."] \
+ "show help"
+ gdb_test "help set print test-undoc-param" \
+ [multi_line \
+ "Set the current value of 'print test-undoc-param'\\." \
+ "This command is not documented\\."] \
+ "set help"
+ gdb_test "help set print" "set print test-undoc-param -- Set the current value of 'print test-undoc-param'\\..*" "general help"
}
# Test a parameter with a restricted range, where we need to notify the user
@@ -379,13 +397,85 @@ gdb_test_no_output "guile (register-parameter! prev-ambig)"
with_test_prefix "previously-ambiguous" {
gdb_test "guile (print (parameter-value prev-ambig))" "= #f" "parameter value, false"
- gdb_test "show print s" "Command is not documented is off." "show parameter off"
+ gdb_test "show print s" \
+ "The current value of 'print s' is off\\." "show parameter off"
gdb_test_no_output "set print s on"
- gdb_test "show print s" "Command is not documented is on." "show parameter on"
+ gdb_test "show print s" \
+ "The current value of 'print s' is on\\." "show parameter on"
gdb_test "guile (print (parameter-value prev-ambig))" "= #t" "parameter value, true"
- gdb_test "help show print s" "This command is not documented." "show help"
- gdb_test "help set print s" "This command is not documented." "set help"
- gdb_test "help set print" "set print s -- This command is not documented.*" "general help"
+ gdb_test "help show print s" \
+ [multi_line \
+ "^Show the current value of 'print s'\\." \
+ "This command is not documented\\."] \
+ "show help"
+ gdb_test "help set print s" \
+ [multi_line \
+ "Set the current value of 'print s'\\." \
+ "This command is not documented\\."] \
+ "set help"
+ gdb_test "help set print" \
+ "set print s -- Set the current value of 'print s'\\..*" \
+ "general help"
+}
+
+gdb_test_multiline "create set/show foo1 prefix commands" \
+ "guile" "" \
+ "(register-command! (make-command \"set foo1\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:prefix? #t))" "" \
+ "(register-command! (make-command \"show foo1\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:prefix? #t))" "" \
+ "end"
+
+gdb_test_multiline "create 'foo bar' parameter" \
+ "guile" "" \
+ "(register-parameter! (make-parameter \"foo bar\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:parameter-type PARAM_BOOLEAN" "" \
+ " #:show-func (lambda (self value)" "" \
+ " (format #f \"The state of 'foo bar' is ~a.\" value))" "" \
+ " #:initial-value #t))" "" \
+ "end"
+
+gdb_test "show foo1 bar" "^The state of 'foo bar' is on\\." "show parameter 'foo bar'"
+
+gdb_test_multiline "create set/show foo2 prefix commands" \
+ "guile" "" \
+ "(register-command! (make-command \"set foo2\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:prefix? #t))" "" \
+ "(register-command! (make-command \"show foo2\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:prefix? #t))" "" \
+ "end" ""
+
+gdb_test_multiline "create ambiguous 'foo baz' parameter" \
+ "guile" "" \
+ "(register-parameter! (make-parameter \"foo baz\"" "" \
+ " #:command-class COMMAND_OBSCURE" "" \
+ " #:parameter-type PARAM_BOOLEAN" "" \
+ " #:show-func (lambda (self value)" "" \
+ " (format #f \"The state of 'foo baz' is ~a.\" value))" "" \
+ " #:initial-value #t))" "" \
+ "end" \
+ [multi_line \
+ "Out of range: could not find command prefix 'foo' in position 1: \"foo baz\"" \
+ "Error while executing Scheme code."]
+
+with_test_prefix "empty doc string" {
+ gdb_test_multiline "empty doc string parameter" \
+ "guile" "" \
+ "(register-parameter! (make-parameter \"empty-doc-string\"" "" \
+ " #:command-class COMMAND_NONE" "" \
+ " #:parameter-type PARAM_ZINTEGER" "" \
+ " #:doc \"\"" "" \
+ " #:set-doc \"Set doc string.\"" "" \
+ " #:show-doc \"Show doc string.\"))" "" \
+ "end"
+
+ gdb_test "help set empty-doc-string" "^Set doc string\\."
+ gdb_test "help show empty-doc-string" "^Show doc string\\."
}
rename scm_param_test_maybe_no_output ""
diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp
index b84f908..dab6275 100644
--- a/gdb/testsuite/gdb.multi/tids.exp
+++ b/gdb/testsuite/gdb.multi/tids.exp
@@ -290,7 +290,7 @@ with_test_prefix "two inferiors" {
# Try both the convenience variable and the literal number.
foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } {
set expected [string_to_regexp $thr]
- gdb_test "info threads $thr" "No threads match '${expected}'."
+ gdb_test "info threads $thr" "No threads matched\\."
# "info threads" works like a filter. If there's any other
# valid thread in the list, there's no error.
info_threads "$thr 1.1" "1.1"
@@ -412,7 +412,7 @@ with_test_prefix "two inferiors" {
# Check that we do parse the inferior number and don't confuse it.
gdb_test "info threads 3.1" \
- "No threads match '3.1'\."
+ "No threads matched\\."
}
if { [allow_python_tests] } {
diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp
index f76c176..5ed52a2 100644
--- a/gdb/testsuite/gdb.python/py-cmd.exp
+++ b/gdb/testsuite/gdb.python/py-cmd.exp
@@ -328,4 +328,31 @@ proc_with_prefix test_command_redefining_itself {} {
"call command redefining itself 2"
}
+# Try to create commands using unknown prefixes and check GDB gives an
+# error. There's also a test in here for an ambiguous prefix, which
+# gives the same error.
+proc_with_prefix test_unknown_prefix {} {
+ clean_restart
+
+ gdb_test_no_output "python gdb.Command('foo1', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('foo cmd', gdb.COMMAND_NONE)"
+
+ foreach prefix { "xxx" "foo xxx" "foo1 xxx" } {
+ gdb_test "python gdb.Command('$prefix cmd', gdb.COMMAND_NONE)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
+
+ gdb_test_no_output "python gdb.Command('foo2', gdb.COMMAND_NONE, prefix=True)"
+
+ foreach prefix { "foo" "foo xxx" "foo1 xxx" "foo2 xxx" } {
+ gdb_test "python gdb.Command('$prefix cmd2', gdb.COMMAND_NONE)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
+}
+
test_command_redefining_itself
+test_unknown_prefix
diff --git a/gdb/testsuite/gdb.python/py-parameter-prefix.exp b/gdb/testsuite/gdb.python/py-parameter-prefix.exp
new file mode 100644
index 0000000..aa2f84a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-parameter-prefix.exp
@@ -0,0 +1,285 @@
+# Copyright (C) 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/>.
+
+# This file is part of the GDB testsuite. It tests
+# gdb.ParameterPrefix. See each of the test procs for a full
+# description of what is being tested.
+
+load_lib gdb-python.exp
+
+require allow_python_tests
+
+clean_restart
+
+# Helper proc to generate the output of 'help MODE PREFIX', where MODE
+# will be either 'set' or 'show'. The HELP_TEXT is the expected help
+# text for this prefix command, this should not be a regexp, as this
+# proc converts the text to a regexp.
+#
+# Return a single regexp which should match the output.
+proc make_help_re { mode prefix help_text } {
+ if { $mode == "set" } {
+ set word "Set"
+ } else {
+ set word "Show"
+ }
+
+ set help_re [string_to_regexp $help_text]
+
+ return \
+ [multi_line \
+ "$help_re" \
+ "" \
+ "List of \"$mode $prefix\" subcommands:" \
+ "" \
+ "$mode $prefix param-1 -- $word the current value of '$prefix param-1'\\." \
+ "" \
+ "Type \"help $mode $prefix\" followed by subcommand name for full documentation\\." \
+ "Type \"apropos word\" to search for commands related to \"word\"\\." \
+ "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \
+ "Command name abbreviations are allowed if unambiguous\\."]
+}
+
+# Create gdb.ParameterPrefix without using a sub-class, both with, and
+# without a doc string. For the doc string case, test single line,
+# and multi-line doc strings.
+proc_with_prefix test_basic_usage {} {
+ gdb_test_multiline "some basic ParameterPrefix usage" \
+ "python" "" \
+ "gdb.ParameterPrefix('prefix-1', gdb.COMMAND_NONE)" "" \
+ "gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "gdb.ParameterPrefix('prefix-2', gdb.COMMAND_NONE," "" \
+ " \"\"\"This is prefix-2 help string.\"\"\")" "" \
+ "gdb.Parameter('prefix-2 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "gdb.ParameterPrefix('prefix-3', gdb.COMMAND_NONE," "" \
+ " \"\"\"This is prefix-3 help string." "" \
+ " " "" \
+ " This help text spans multiple lines.\"\"\")" "" \
+ "gdb.Parameter('prefix-3 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "end"
+
+ foreach mode { "set" "show" } {
+ gdb_test "help $mode prefix-1" \
+ [make_help_re $mode "prefix-1" \
+ "This command is not documented."]
+
+ gdb_test "help $mode prefix-2" \
+ [make_help_re $mode "prefix-2" \
+ "This is prefix-2 help string."]
+
+ gdb_test "help $mode prefix-3" \
+ [make_help_re $mode "prefix-3" \
+ [multi_line \
+ "This is prefix-3 help string." \
+ "" \
+ "This help text spans multiple lines."]]
+
+ foreach prefix { prefix-1 prefix-2 prefix-3 } {
+ gdb_test "$mode $prefix xxx" \
+ "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\."
+ }
+ }
+}
+
+# Create a sub-class of gdb.ParameterPrefix, but don't do anything
+# particularly interesting. Again test the with and without
+# documentation string cases.
+proc_with_prefix test_simple_sub_class {} {
+ gdb_test_multiline "some basic ParameterPrefix usage" \
+ "python" "" \
+ "class BasicParamPrefix(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ "BasicParamPrefix('prefix-4')" "" \
+ "gdb.Parameter('prefix-4 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class BasicParamPrefixWithSingleLineDoc(gdb.ParameterPrefix):" "" \
+ " \"\"\"This is a single line doc string.\"\"\"" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ "BasicParamPrefixWithSingleLineDoc('prefix-5')" "" \
+ "gdb.Parameter('prefix-5 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class BasicParamPrefixWithMultiLineDoc(gdb.ParameterPrefix):" "" \
+ " \"\"\"This is a multi line doc string." "" \
+ " " "" \
+ " The rest of the doc string is here.\"\"\"" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ "BasicParamPrefixWithMultiLineDoc('prefix-6')" "" \
+ "gdb.Parameter('prefix-6 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class BasicParamPrefixWithDocParameter(gdb.ParameterPrefix):" "" \
+ " \"\"\"This is an unsused doc string.\"\"\"" "" \
+ " def __init__(self, name, doc):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE, doc)" "" \
+ "BasicParamPrefixWithDocParameter('prefix-7'," "" \
+ " \"\"\"The doc string text is here.\"\"\")" "" \
+ "gdb.Parameter('prefix-7 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "end"
+
+ foreach mode { "set" "show" } {
+ gdb_test "help $mode prefix-4" \
+ [make_help_re $mode "prefix-4" \
+ "This command is not documented."]
+
+ gdb_test "help $mode prefix-5" \
+ [make_help_re $mode "prefix-5" \
+ "This is a single line doc string."]
+
+ gdb_test "help $mode prefix-6" \
+ [make_help_re $mode "prefix-6" \
+ [multi_line \
+ "This is a multi line doc string." \
+ "" \
+ "The rest of the doc string is here."]]
+
+ gdb_test "help $mode prefix-7" \
+ [make_help_re $mode "prefix-7" \
+ "The doc string text is here."]
+
+ foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } {
+ gdb_test "$mode $prefix xxx" \
+ "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\."
+ }
+ }
+}
+
+# Create a sub-class of gdb.ParameterPrefix, and make use of
+# 'invoke_set' and 'invoke_show'. Test that the invoke method is
+# executed when expected, and that, by default, these invoke methods
+# repeat when the user issues an empty command.
+proc_with_prefix test_prefix_with_invoke {} {
+ gdb_test_multiline "ParameterPrefix with invoke_set" \
+ "python" "" \
+ "class PrefixWithInvokeSet(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ " def invoke_set(self, args, from_tty):" "" \
+ " print(f\"invoke_set (a): \\\"{args}\\\" {from_tty}\")" "" \
+ "PrefixWithInvokeSet('prefix-8')" "" \
+ "gdb.Parameter('prefix-8 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class PrefixWithInvokeShow(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ " def invoke_show(self, args, from_tty):" "" \
+ " print(f\"invoke_show (b): \\\"{args}\\\" {from_tty}\")" "" \
+ "PrefixWithInvokeShow('prefix-9')" "" \
+ "gdb.Parameter('prefix-9 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class PrefixWithBothInvoke(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ " def invoke_set(self, args, from_tty):" "" \
+ " print(f\"invoke_set (c): \\\"{args}\\\" {from_tty}\")" "" \
+ " def invoke_show(self, args, from_tty):" "" \
+ " print(f\"invoke_show (d): \\\"{args}\\\" {from_tty}\")" "" \
+ "PrefixWithBothInvoke('prefix-10')" "" \
+ "gdb.Parameter('prefix-10 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "end"
+
+ gdb_test "set prefix-8 xxx yyy" \
+ "^invoke_set \\(a\\): \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^\r\ninvoke_set \\(a\\): \"xxx yyy\" True" \
+ "repeat set prefix-8 xxx yyy"
+
+ gdb_test "show prefix-8 xxx yyy" \
+ "^Undefined show prefix-8 command: \"xxx yyy\"\\. Try \"help show prefix-8\"\\."
+
+ gdb_test "set prefix-9 xxx yyy" \
+ "^Undefined set prefix-9 command: \"xxx yyy\"\\. Try \"help set prefix-9\"\\."
+
+ gdb_test "show prefix-9 xxx yyy" \
+ "^invoke_show \\(b\\): \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^\r\ninvoke_show \\(b\\): \"xxx yyy\" True" \
+ "repeat show prefix-9 xxx yyy"
+
+ gdb_test "set prefix-10 xxx yyy" \
+ "^invoke_set \\(c\\): \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^\r\ninvoke_set \\(c\\): \"xxx yyy\" True" \
+ "repeat set prefix-10 xxx yyy"
+
+ gdb_test "show prefix-10 xxx yyy" \
+ "^invoke_show \\(d\\): \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^\r\ninvoke_show \\(d\\): \"xxx yyy\" True" \
+ "repeat show prefix-10 xxx yyy"
+}
+
+# Create ParameterPrefix sub-classes that make use of the
+# dont_repeat() method. Check that the relevant set/show invoke
+# callback doesn't repeat when an empty command is used.
+proc_with_prefix test_dont_repeat {} {
+ gdb_test_multiline "ParameterPrefix with invoke_set and dont_repeat" \
+ "python" "" \
+ "class PrefixWithInvokeAndDoNotRepeatSet(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ " def invoke_set(self, args, from_tty):" "" \
+ " self.dont_repeat()" "" \
+ " print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \
+ " def invoke_show(self, args, from_tty):" "" \
+ " print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \
+ "PrefixWithInvokeAndDoNotRepeatSet('prefix-11')" "" \
+ "gdb.Parameter('prefix-11 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "class PrefixWithInvokeAndDoNotRepeatShow(gdb.ParameterPrefix):" "" \
+ " def __init__(self, name):" "" \
+ " super().__init__(name, gdb.COMMAND_NONE)" "" \
+ " def invoke_set(self, args, from_tty):" "" \
+ " print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \
+ " def invoke_show(self, args, from_tty):" "" \
+ " self.dont_repeat()" "" \
+ " print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \
+ "PrefixWithInvokeAndDoNotRepeatShow('prefix-12')" "" \
+ "gdb.Parameter('prefix-12 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ "end"
+
+ gdb_test "set prefix-11 xxx yyy" \
+ "^invoke_set: \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^" \
+ "repeat set prefix-11 xxx yyy"
+
+ gdb_test "show prefix-11 xxx yyy" \
+ "^invoke_show: \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "invoke_show: \"xxx yyy\" True" \
+ "repeat show prefix-11 xxx yyy"
+
+ gdb_test "set prefix-12 xxx yyy" \
+ "^invoke_set: \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^\r\ninvoke_set: \"xxx yyy\" True" \
+ "repeat set prefix-12 xxx yyy"
+
+ gdb_test "show prefix-12 xxx yyy" \
+ "^invoke_show: \"xxx yyy\" True"
+
+ send_gdb "\n"
+ gdb_test "" "^" \
+ "repeat show prefix-12 xxx yyy"
+}
+
+test_basic_usage
+test_simple_sub_class
+test_prefix_with_invoke
+test_dont_repeat
diff --git a/gdb/testsuite/gdb.python/py-parameter.exp b/gdb/testsuite/gdb.python/py-parameter.exp
index c15bef1..2ca56dc 100644
--- a/gdb/testsuite/gdb.python/py-parameter.exp
+++ b/gdb/testsuite/gdb.python/py-parameter.exp
@@ -346,6 +346,91 @@ proc_with_prefix test_really_undocumented_parameter { } {
"test general help"
}
+# Test a parameter in which the __doc__ string is empty or None.
+proc_with_prefix test_empty_doc_parameter {} {
+ gdb_test_multiline "empty __doc__ parameter" \
+ "python" "" \
+ "class EmptyDocParam(gdb.Parameter):" "" \
+ " __doc__ = \"\"" "" \
+ " def __init__(self, name):" "" \
+ " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "test_empty_doc_param = EmptyDocParam('print test-empty-doc-param')" ""\
+ "end"
+
+ # Setting the __doc__ string to empty means GDB will completely
+ # elide it from the output.
+ gdb_test "help set print test-empty-doc-param" \
+ "^Set the current value of 'print test-empty-doc-param'\\."
+
+ gdb_test_multiline "None __doc__ parameter" \
+ "python" "" \
+ "class NoneDocParam(gdb.Parameter):" "" \
+ " __doc__ = None" "" \
+ " def __init__(self, name):" "" \
+ " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "test_none_doc_param = NoneDocParam('print test-none-doc-param')" ""\
+ "end"
+
+ # Setting the __doc__ string to None, or anything else that isn't
+ # a string, causes GDB to use a default string instead.
+ gdb_test "help set print test-none-doc-param" \
+ [multi_line \
+ "^Set the current value of 'print test-none-doc-param'\\." \
+ "This command is not documented\\."]
+}
+
+# Test a parameter in which the set_doc/show_doc strings are either
+# empty, or None.
+proc_with_prefix test_empty_set_show_doc_parameter {} {
+ gdb_test_multiline "empty set/show doc parameter" \
+ "python" "" \
+ "class EmptySetShowParam(gdb.Parameter):" "" \
+ " set_doc = \"\"" "" \
+ " show_doc = \"\"" "" \
+ " def __init__(self, name):" "" \
+ " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "test_empty_set_show_param = EmptySetShowParam('print test-empty-set-show-param')" ""\
+ "end"
+
+ # Setting the set_doc/show_doc string to empty means GDB will use
+ # a suitable default string.
+ gdb_test "help set print test-empty-set-show-param" \
+ [multi_line \
+ "^Set the current value of 'print test-empty-set-show-param'\\." \
+ "This command is not documented\\."]
+
+ gdb_test "help show print test-empty-set-show-param" \
+ [multi_line \
+ "^Show the current value of 'print test-empty-set-show-param'\\." \
+ "This command is not documented\\."]
+
+ gdb_test_multiline "None set/show doc parameter" \
+ "python" "" \
+ "class NoneSetShowParam(gdb.Parameter):" "" \
+ " set_doc = None" "" \
+ " show_doc = None" "" \
+ " def __init__(self, name):" "" \
+ " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "test_none_set_show_param = NoneSetShowParam('print test-none-set-show-param')" ""\
+ "end"
+
+ # Setting the set_doc/show_doc string to None (or any non-string
+ # value) means GDB will use a suitable default string.
+ gdb_test "help set print test-none-set-show-param" \
+ [multi_line \
+ "^Set the current value of 'print test-none-set-show-param'\\." \
+ "This command is not documented\\."]
+
+ gdb_test "help show print test-none-set-show-param" \
+ [multi_line \
+ "^Show the current value of 'print test-none-set-show-param'\\." \
+ "This command is not documented\\."]
+}
+
# Test deprecated API. Do not use in your own implementations.
proc_with_prefix test_deprecated_api_parameter { } {
clean_restart
@@ -669,6 +754,43 @@ proc_with_prefix test_ambiguous_parameter {} {
"Parameter .* is ambiguous.*Error occurred in Python.*"
gdb_test "python print(gdb.parameter('test-ambiguous-value-1a'))" \
"Could not find parameter.*Error occurred in Python.*"
+
+ # Create command prefixs 'set foo1' and 'show foo1'.
+ gdb_test_no_output "python gdb.Command('set foo1', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('show foo1', gdb.COMMAND_NONE, prefix=True)"
+
+ # Create a parameter under 'foo1', but use a truncated prefix. At
+ # this point though, the prefix is not ambiguous.
+ gdb_test_no_output "python gdb.Parameter('foo bar', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)"
+ gdb_test "python print(gdb.parameter('foo1 bar'))" "False"
+
+ # Create another prefix command, similar in name to the first.
+ gdb_test_no_output "python gdb.Command('set foo2', gdb.COMMAND_NONE, prefix=True)"
+ gdb_test_no_output "python gdb.Command('show foo2', gdb.COMMAND_NONE, prefix=True)"
+
+ # An attempt to create a parameter using an ambiguous prefix will give an error.
+ gdb_test "python gdb.Parameter('foo baz', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix foo\\." \
+ "Error occurred in Python: Could not find command prefix foo\\."]
+}
+
+# Check that creating a gdb.Parameter with an unknown command prefix results in an error.
+proc_with_prefix test_unknown_prefix {} {
+ gdb_test_multiline "create parameter" \
+ "python" "" \
+ "class UnknownPrefixParam(gdb.Parameter):" "" \
+ " def __init__ (self, name):" "" \
+ " super().__init__ (name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \
+ " self.value = True" "" \
+ "end"
+
+ foreach prefix { "unknown-prefix" "style unknown-prefix" "style disassembler unknown-prefix"} {
+ gdb_test "python UnknownPrefixParam('$prefix new-param')" \
+ [multi_line \
+ "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \
+ "Error occurred in Python: Could not find command prefix $prefix\\."]
+ }
}
test_directories
@@ -679,11 +801,14 @@ test_color_parameter
test_file_parameter
test_undocumented_parameter
test_really_undocumented_parameter
+test_empty_doc_parameter
+test_empty_set_show_doc_parameter
test_deprecated_api_parameter
test_gdb_parameter
test_integer_parameter
test_throwing_parameter
test_language
test_ambiguous_parameter
+test_unknown_prefix
rename py_param_test_maybe_no_output ""
diff --git a/gdb/testsuite/gdb.threads/current-lwp-dead.exp b/gdb/testsuite/gdb.threads/current-lwp-dead.exp
index 7aa7ab9..c8364df 100644
--- a/gdb/testsuite/gdb.threads/current-lwp-dead.exp
+++ b/gdb/testsuite/gdb.threads/current-lwp-dead.exp
@@ -47,6 +47,6 @@ gdb_breakpoint $line
gdb_continue_to_breakpoint "fn_return" ".*at-fn_return.*"
# Confirm thread 2 is really gone.
-gdb_test "info threads 2" "No threads match '2'\\."
+gdb_test "info threads 2" "No threads matched\\."
gdb_continue_to_end "" continue 1
diff --git a/gdb/testsuite/gdb.threads/info-threads-options.c b/gdb/testsuite/gdb.threads/info-threads-options.c
new file mode 100644
index 0000000..2c4cd85
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/info-threads-options.c
@@ -0,0 +1,77 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2022-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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define NUM 4
+
+static pthread_barrier_t threads_started_barrier;
+
+static void
+stop_here ()
+{
+}
+
+static void
+spin ()
+{
+ while (1)
+ usleep (1);
+}
+
+static void *
+work (void *arg)
+{
+ int id = *(int *) arg;
+
+ pthread_barrier_wait (&threads_started_barrier);
+
+ if (id % 2 == 0)
+ stop_here ();
+ else
+ spin ();
+
+ pthread_exit (NULL);
+}
+
+int
+main ()
+{
+ /* Ensure we stop if GDB crashes and DejaGNU fails to kill us. */
+ alarm (10);
+
+ pthread_t threads[NUM];
+ int ids[NUM];
+
+ pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
+
+ for (int i = 0; i < NUM; i++)
+ {
+ ids[i] = i;
+ pthread_create (&threads[i], NULL, work, &ids[i]);
+ }
+
+ /* Wait until all threads are seen running. */
+ pthread_barrier_wait (&threads_started_barrier);
+
+ stop_here ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/info-threads-options.exp b/gdb/testsuite/gdb.threads/info-threads-options.exp
new file mode 100644
index 0000000..38e4e67
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/info-threads-options.exp
@@ -0,0 +1,131 @@
+# Copyright (C) 2022-2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test the filter flags of the "info threads" command.
+
+standard_testfile
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable debug] != "" } {
+ return -1
+}
+
+save_vars { GDBFLAGS } {
+ append GDBFLAGS " -ex \"set non-stop on\""
+ clean_restart $binfile
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint "stop_here"
+gdb_test_multiple "continue -a&" "" {
+ -re "Continuing.\r\n$gdb_prompt " {
+ pass $gdb_test_name
+ }
+}
+
+set expected_hits 3
+set fill "\[^\r\n\]+"
+set num_hits 0
+gdb_test_multiple "" "hit the breakpoint" -lbl {
+ -re "\r\nThread ${fill} hit Breakpoint ${decimal}," {
+ incr num_hits
+ if {$num_hits < $expected_hits} {
+ exp_continue
+ }
+ }
+}
+gdb_assert {$num_hits == $expected_hits} "expected threads hit the bp"
+
+# Count the number of running/stopped threads reported
+# by the "info threads" command. We also capture thread ids
+# for additional tests.
+set running_tid "invalid"
+set stopped_tid "invalid"
+
+set eol "(?=\r\n)"
+
+foreach_with_prefix flag {"" "-running" "-stopped" "-running -stopped"} {
+ set num_running 0
+ set num_stopped 0
+ gdb_test_multiple "info threads $flag" "info threads $flag" -lbl {
+ -re "Id${fill}Target Id${fill}Frame${fill}${eol}" {
+ exp_continue
+ }
+ -re "^\r\n. (${decimal})${fill}Thread ${fill}.running.${eol}" {
+ incr num_running
+ set running_tid $expect_out(1,string)
+ exp_continue
+ }
+ -re "^\r\n. (${decimal})${fill}Thread ${fill}stop_here ${fill}${eol}" {
+ incr num_stopped
+ set stopped_tid $expect_out(1,string)
+ exp_continue
+ }
+ -re "^\r\n$gdb_prompt $" {
+ pass $gdb_test_name
+ }
+ }
+
+ if {$flag eq "-running"} {
+ gdb_assert {$num_running == 2} "num running"
+ gdb_assert {$num_stopped == 0} "num stopped"
+ } elseif {$flag eq "-stopped"} {
+ gdb_assert {$num_running == 0} "num running"
+ gdb_assert {$num_stopped == 3} "num stopped"
+ } else {
+ gdb_assert {$num_running == 2} "num running"
+ gdb_assert {$num_stopped == 3} "num stopped"
+ }
+}
+
+verbose -log "running_tid=$running_tid, stopped_tid=$stopped_tid"
+
+# Test specifying thread ids.
+gdb_test "info threads -running $stopped_tid" \
+ "No threads matched\\." \
+ "info thread -running for a stopped thread"
+gdb_test "info threads -stopped $running_tid" \
+ "No threads matched\\." \
+ "info thread -stopped for a running thread"
+
+set ws "\[ \t\]+"
+foreach tid "\"$running_tid\" \"$running_tid $stopped_tid\"" {
+ gdb_test "info threads -running $tid" \
+ [multi_line \
+ "${ws}Id${ws}Target Id${ws}Frame${ws}" \
+ "${ws}${running_tid}${ws}Thread ${fill}.running."] \
+ "info thread -running with [llength $tid] thread ids"
+}
+
+foreach tid "\"$stopped_tid\" \"$stopped_tid $running_tid\"" {
+ gdb_test "info threads -stopped $tid" \
+ [multi_line \
+ "${ws}Id${ws}Target Id${ws}Frame${ws}" \
+ "${ws}${stopped_tid}${ws}Thread ${fill} stop_here ${fill}"] \
+ "info thread -stopped with [llength $tid] thread ids"
+}
+
+gdb_test_multiple "info threads -stopped -running $stopped_tid $running_tid" \
+ "filter flags and tids combined" {
+ -re -wrap ".*stop_here.*running.*" {
+ pass $gdb_test_name
+ }
+ -re -wrap ".*running.*stop_here.*" {
+ pass $gdb_test_name
+ }
+}
diff --git a/gdb/testsuite/gdb.threads/thread-bp-deleted.exp b/gdb/testsuite/gdb.threads/thread-bp-deleted.exp
index 2eadd38..8cabb70 100644
--- a/gdb/testsuite/gdb.threads/thread-bp-deleted.exp
+++ b/gdb/testsuite/gdb.threads/thread-bp-deleted.exp
@@ -147,7 +147,7 @@ if {$is_remote} {
exp_continue
}
- -re "No threads match '99'\\.\r\n$gdb_prompt $" {
+ -re "No threads matched\\.\r\n$gdb_prompt $" {
if {!$saw_thread_exited && !$saw_bp_deleted && $attempt_count > 0} {
sleep 1
incr attempt_count -1
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 2a5d37c..49ef0d5 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2301,7 +2301,8 @@ proc default_gdb_exit {} {
}
}
- if { [is_remote host] && [board_info host exists fileid] } {
+ if { ([is_remote host] && [board_info host exists fileid])
+ || [istarget *-*-mingw*] } {
send_gdb "quit\n"
gdb_expect 10 {
-re "y or n" {
@@ -6920,7 +6921,7 @@ proc kill_wait_spawned_process { proc_spawn_id } {
proc spawn_id_get_pid { spawn_id } {
set testpid [exp_pid -i $spawn_id]
- if { [istarget "*-*-cygwin*"] } {
+ if { [istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"] } {
# testpid is the Cygwin PID, GDB uses the Windows PID, which
# might be different due to the way fork/exec works.
set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ]
diff --git a/gdb/thread.c b/gdb/thread.c
index b659463..0228027 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1038,6 +1038,37 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread)
&& pc < thread->control.step_range_end);
}
+/* The options for the "info threads" command. */
+
+struct info_threads_opts
+{
+ /* For "-gid". */
+ bool show_global_ids = false;
+ /* For "-running". */
+ bool show_running_threads = false;
+ /* For "-stopped". */
+ bool show_stopped_threads = false;
+};
+
+static const gdb::option::option_def info_threads_option_defs[] = {
+
+ gdb::option::flag_option_def<info_threads_opts> {
+ "gid",
+ [] (info_threads_opts *opts) { return &opts->show_global_ids; },
+ N_("Show global thread IDs."),
+ },
+ gdb::option::flag_option_def<info_threads_opts> {
+ "running",
+ [] (info_threads_opts *opts) { return &opts->show_running_threads; },
+ N_("Show running threads only."),
+ },
+ gdb::option::flag_option_def<info_threads_opts> {
+ "stopped",
+ [] (info_threads_opts *opts) { return &opts->show_stopped_threads; },
+ N_("Show stopped threads only."),
+ },
+};
+
/* Helper for print_thread_info. Returns true if THR should be
printed. If REQUESTED_THREADS, a list of GDB ids/ranges, is not
NULL, only print THR if its ID is included in the list. GLOBAL_IDS
@@ -1046,11 +1077,13 @@ pc_in_thread_step_range (CORE_ADDR pc, struct thread_info *thread)
is a thread from the process PID. Otherwise, threads from all
attached PIDs are printed. If both REQUESTED_THREADS is not NULL
and PID is not -1, then the thread is printed if it belongs to the
- specified process. Otherwise, an error is raised. */
+ specified process. Otherwise, an error is raised. OPTS is the
+ options of the "info threads" command. */
static bool
-should_print_thread (const char *requested_threads, int default_inf_num,
- int global_ids, int pid, struct thread_info *thr)
+should_print_thread (const char *requested_threads,
+ const info_threads_opts &opts, int default_inf_num,
+ int global_ids, int pid, thread_info *thr)
{
if (requested_threads != NULL && *requested_threads != '\0')
{
@@ -1075,7 +1108,17 @@ should_print_thread (const char *requested_threads, int default_inf_num,
if (thr->state == THREAD_EXITED)
return false;
- return true;
+ bool is_stopped = (thr->state == THREAD_STOPPED);
+ if (opts.show_stopped_threads && is_stopped)
+ return true;
+
+ bool is_running = (thr->state == THREAD_RUNNING);
+ if (opts.show_running_threads && is_running)
+ return true;
+
+ /* If the user did not pass a filter flag, show the thread. */
+ return (!opts.show_stopped_threads
+ && !opts.show_running_threads);
}
/* Return the string to display in "info threads"'s "Target Id"
@@ -1104,8 +1147,8 @@ thread_target_id_str (thread_info *tp)
static void
do_print_thread (ui_out *uiout, const char *requested_threads,
- int global_ids, int pid, int show_global_ids,
- int default_inf_num, thread_info *tp,
+ const info_threads_opts &opts, int global_ids,
+ int pid, int default_inf_num, thread_info *tp,
thread_info *current_thread)
{
int core;
@@ -1114,7 +1157,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads,
if (current_thread != nullptr)
switch_to_thread (current_thread);
- if (!should_print_thread (requested_threads, default_inf_num,
+ if (!should_print_thread (requested_threads, opts, default_inf_num,
global_ids, pid, tp))
return;
@@ -1130,7 +1173,7 @@ do_print_thread (ui_out *uiout, const char *requested_threads,
uiout->field_string ("id-in-tg", print_thread_id (tp));
}
- if (show_global_ids || uiout->is_mi_like_p ())
+ if (opts.show_global_ids || uiout->is_mi_like_p ())
uiout->field_signed ("id", tp->global_num);
/* Switch to the thread (and inferior / target). */
@@ -1191,23 +1234,22 @@ do_print_thread (ui_out *uiout, const char *requested_threads,
static void
print_thread (ui_out *uiout, const char *requested_threads,
- int global_ids, int pid, int show_global_ids,
+ const info_threads_opts &opts, int global_ids, int pid,
int default_inf_num, thread_info *tp, thread_info *current_thread)
{
do_with_buffered_output (do_print_thread, uiout, requested_threads,
- global_ids, pid, show_global_ids,
- default_inf_num, tp, current_thread);
+ opts, global_ids, pid, default_inf_num, tp,
+ current_thread);
}
/* Like print_thread_info, but in addition, GLOBAL_IDS indicates
whether REQUESTED_THREADS is a list of global or per-inferior
- thread ids. */
+ thread ids. OPTS is the options of the "info threads" command. */
static void
print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
- int global_ids, int pid,
- int show_global_ids)
+ const info_threads_opts &opts, int global_ids, int pid)
{
int default_inf_num = current_inferior ()->num;
@@ -1235,19 +1277,21 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
list_emitter.emplace (uiout, "threads");
else
{
- int n_threads = 0;
+ int n_matching_threads = 0;
/* The width of the "Target Id" column. Grown below to
accommodate the largest entry. */
size_t target_id_col_width = 17;
for (thread_info *tp : all_threads ())
{
+ any_thread = true;
+
/* In case REQUESTED_THREADS contains $_thread. */
if (current_thread != nullptr)
switch_to_thread (current_thread);
- if (!should_print_thread (requested_threads, default_inf_num,
- global_ids, pid, tp))
+ if (!should_print_thread (requested_threads, opts,
+ default_inf_num, global_ids, pid, tp))
continue;
/* Switch inferiors so we're looking at the right
@@ -1258,25 +1302,24 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
= std::max (target_id_col_width,
thread_target_id_str (tp).size ());
- ++n_threads;
+ ++n_matching_threads;
}
- if (n_threads == 0)
+ if (n_matching_threads == 0)
{
- if (requested_threads == NULL || *requested_threads == '\0')
+ if (!any_thread)
uiout->message (_("No threads.\n"));
else
- uiout->message (_("No threads match '%s'.\n"),
- requested_threads);
+ uiout->message (_("No threads matched.\n"));
return;
}
- table_emitter.emplace (uiout, show_global_ids ? 5 : 4,
- n_threads, "threads");
+ table_emitter.emplace (uiout, opts.show_global_ids ? 5 : 4,
+ n_matching_threads, "threads");
uiout->table_header (1, ui_left, "current", "");
uiout->table_header (4, ui_left, "id-in-tg", "Id");
- if (show_global_ids)
+ if (opts.show_global_ids)
uiout->table_header (4, ui_left, "id", "GId");
uiout->table_header (target_id_col_width, ui_left,
"target-id", "Target Id");
@@ -1287,13 +1330,11 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
for (inferior *inf : all_inferiors ())
for (thread_info *tp : inf->threads ())
{
- any_thread = true;
-
if (tp == current_thread && tp->state == THREAD_EXITED)
current_exited = true;
- print_thread (uiout, requested_threads, global_ids, pid,
- show_global_ids, default_inf_num, tp, current_thread);
+ print_thread (uiout, requested_threads, opts, global_ids, pid,
+ default_inf_num, tp, current_thread);
}
/* This end scope restores the current thread and the frame
@@ -1322,27 +1363,10 @@ void
print_thread_info (struct ui_out *uiout, const char *requested_threads,
int pid)
{
- print_thread_info_1 (uiout, requested_threads, 1, pid, 0);
+ info_threads_opts opts;
+ print_thread_info_1 (uiout, requested_threads, opts, 1, pid);
}
-/* The options for the "info threads" command. */
-
-struct info_threads_opts
-{
- /* For "-gid". */
- bool show_global_ids = false;
-};
-
-static const gdb::option::option_def info_threads_option_defs[] = {
-
- gdb::option::flag_option_def<info_threads_opts> {
- "gid",
- [] (info_threads_opts *opts) { return &opts->show_global_ids; },
- N_("Show global thread IDs."),
- },
-
-};
-
/* Create an option_def_group for the "info threads" options, with
IT_OPTS as context. */
@@ -1367,7 +1391,7 @@ info_threads_command (const char *arg, int from_tty)
gdb::option::process_options
(&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp);
- print_thread_info_1 (current_uiout, arg, 0, -1, it_opts.show_global_ids);
+ print_thread_info_1 (current_uiout, arg, it_opts, 0, -1);
}
/* Completer for the "info threads" command. */
diff --git a/gdbsupport/event-loop.cc b/gdbsupport/event-loop.cc
index c080490..e7b21e7 100644
--- a/gdbsupport/event-loop.cc
+++ b/gdbsupport/event-loop.cc
@@ -827,7 +827,8 @@ update_wait_timeout (void)
/* Update the timeout for select/ poll. */
#ifdef HAVE_POLL
if (use_poll)
- gdb_notifier.poll_timeout = timeout.tv_sec * 1000;
+ gdb_notifier.poll_timeout = (timeout.tv_sec * 1000 +
+ (timeout.tv_usec + 1000 - 1) / 1000);
else
#endif /* HAVE_POLL */
{
diff --git a/ld/testsuite/ld-elfvers/vers7.c b/ld/testsuite/ld-elfvers/vers7.c
index 54316c9..a4fb254 100644
--- a/ld/testsuite/ld-elfvers/vers7.c
+++ b/ld/testsuite/ld-elfvers/vers7.c
@@ -2,8 +2,8 @@
* Test program that goes with test7.so
*/
-extern int hide_a();
-extern int show_b();
+extern int hide_a(int e);
+extern int show_b(int e);
int
main()
diff --git a/ld/testsuite/ld-plugin/lto-binutils.exp b/ld/testsuite/ld-plugin/lto-binutils.exp
new file mode 100644
index 0000000..36c7380
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-binutils.exp
@@ -0,0 +1,339 @@
+# Expect script for binutils tests with LTO
+# Copyright (C) 2025 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# Make sure that binutils can correctly handle LTO IR in ELF.
+
+if { !([istarget *-*-linux*]
+ || [istarget arm*-*-uclinuxfdpiceabi]
+ || [istarget *-*-nacl*]
+ || [istarget *-*-gnu*]) || [istarget *ecoff] } then {
+ return
+}
+
+# Check to see if the C and C++ compilers work
+if { ![check_compiler_available] || [which $CXX_FOR_TARGET] == 0 } {
+ return
+}
+
+# These tests require plugin and LTO.
+if { ![check_plugin_api_available]
+ || ![check_lto_available] } {
+ return
+}
+
+set lto_fat ""
+set lto_no_fat ""
+if { [check_lto_fat_available] } {
+ set lto_fat "-ffat-lto-objects"
+ set lto_no_fat "-fno-fat-lto-objects"
+ set no_lto "-fno-lto"
+}
+
+# List contains test-items:
+# 0:program name
+# 1:program options
+# 2:input file
+# 3:output file
+# 4:action list (optional)
+#
+proc run_lto_binutils_test { lto_tests } {
+ global srcdir
+ global subdir
+ global nm
+ global objcopy
+ global objdump
+ global READELF
+ global strip
+ global plug_opt
+
+ foreach testitem $lto_tests {
+ set prog_name [lindex $testitem 0]
+ set prog_options [lindex $testitem 1]
+ set input tmpdir/[lindex $testitem 2]
+ set output tmpdir/[lindex $testitem 3]
+ set actions [lindex $testitem 4]
+ set objfiles {}
+ set is_unresolved 0
+ set failed 0
+
+# eval set prog \$$prog_name
+ switch -- $prog_name {
+ objcopy
+ {
+ set prog $objcopy
+ set prog_output "$output"
+ }
+ strip
+ {
+ set prog $strip
+ set prog_output "-o $output"
+ }
+ default
+ {
+ perror "Unrecognized action $action"
+ set is_unresolved 1
+ break
+ }
+ }
+
+ # Don't leave previous output around
+ if { $output ne "tmpdir/" } {
+ remote_file host delete $output
+ }
+
+ append prog_options " $plug_opt"
+
+ set cmd_options "$prog_options $prog_output $input"
+ set test_name "$prog_name $cmd_options"
+
+ set cmd "$prog $cmd_options"
+ send_log "$cmd\n"
+ set got [remote_exec host "$cmd"]
+ if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+ send_log "$got\n"
+ fail "$test_name"
+ continue
+ }
+
+ if { $failed == 0 } {
+ foreach actionlist $actions {
+ set action [lindex $actionlist 0]
+ set progopts [lindex $actionlist 1]
+
+ # There are actions where we run regexp_diff on the
+ # output, and there are other actions (presumably).
+ # Handling of the former look the same.
+ set dump_prog ""
+ switch -- $action {
+ objdump
+ { set dump_prog $objdump }
+ nm
+ { set dump_prog $nm }
+ readelf
+ { set dump_prog $READELF }
+ default
+ {
+ perror "Unrecognized action $action"
+ set is_unresolved 1
+ break
+ }
+ }
+
+ if { $dump_prog != "" } {
+ set dumpfile [lindex $actionlist 2]
+ set binary $dump_prog
+
+ # Ensure consistent sorting of symbols
+ if {[info exists env(LC_ALL)]} {
+ set old_lc_all $env(LC_ALL)
+ }
+ set env(LC_ALL) "C"
+ set cmd "$binary $progopts $output > tmpdir/dump.out"
+ send_log "$cmd\n"
+ catch "exec $cmd" comp_output
+ if {[info exists old_lc_all]} {
+ set env(LC_ALL) $old_lc_all
+ } else {
+ unset env(LC_ALL)
+ }
+ set comp_output [prune_warnings $comp_output]
+
+ if ![string match "" $comp_output] then {
+ send_log "$comp_output\n"
+ set failed 1
+ break
+ }
+
+ if { [regexp_diff "tmpdir/dump.out" "$srcdir/$subdir/$dumpfile"] } then {
+ verbose -log "output is [file_contents "tmpdir/dump.out"]" 2
+ set failed 1
+ break
+ }
+ }
+ }
+ }
+
+ if { $failed } {
+ fail $test_name
+ } elseif { $is_unresolved } {
+ unresolved $test_name
+ } else {
+ pass $test_name
+ }
+ }
+}
+
+run_cc_link_tests [list \
+ [list \
+ "Build strip-1a.o" \
+ "" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1a.c } \
+ ] \
+ [list \
+ "Build libstrip-1a.a" \
+ "$plug_opt" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1a.c } \
+ {} \
+ "libstrip-1a.a" \
+ ] \
+ [list \
+ "Build strip-1a-fat.o" \
+ "" \
+ "-O2 -flto $lto_fat" \
+ { strip-1a-fat.c } \
+ ] \
+ [list \
+ "Build libstrip-1a-fat.a" \
+ "$plug_opt" \
+ "-O2 -flto $lto_fat" \
+ { strip-1a-fat.c } \
+ {} \
+ "libstrip-1a-fat.a" \
+ ] \
+]
+
+run_lto_binutils_test [list \
+ [list \
+ "strip" \
+ "--strip-unneeded" \
+ "libstrip-1a.a" \
+ "libstrip-1a-s.a" \
+ ] \
+ [list \
+ "strip" \
+ "--strip-unneeded" \
+ "strip-1a.o" \
+ "strip-1a-s.o" \
+ ] \
+ [list \
+ "strip" \
+ "--strip-unneeded -R .gnu.*lto_* -N __gnu_lto_v1" \
+ "libstrip-1a-fat.a" \
+ "libstrip-1a-fat-s.a" \
+ {{readelf -SW strip-1a-fat.rd}} \
+ ] \
+ [list \
+ "strip" \
+ "--strip-unneeded -R .gnu.*lto_* -N __gnu_lto_v1" \
+ "strip-1a-fat.o" \
+ "strip-1a-fat-s.o" \
+ {{readelf -SW strip-1a-fat.rd}} \
+ ] \
+ [list \
+ "strip" \
+ "--strip-unneeded -R .gnu.debuglto_*" \
+ "libstrip-1a-fat.a" \
+ "libstrip-1b-fat-s.a" \
+ {{readelf -SW strip-1b-fat.rd}} \
+ ] \
+ [list \
+ "strip" \
+ "--strip-unneeded -R .gnu.debuglto_*" \
+ "strip-1a-fat.o" \
+ "strip-1b-fat-s.o" \
+ {{readelf -SW strip-1b-fat.rd}} \
+ ] \
+]
+
+run_cc_link_tests [list \
+ [list \
+ "Build strip-1a (strip-1a.o)" \
+ "" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1b.c } \
+ {} \
+ "libstrip-1a" \
+ "C" \
+ "tmpdir/strip-1a.o" \
+ ] \
+ [list \
+ "Build strip-1b (strip-1a-s.o)" \
+ "" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1b.c } \
+ {} \
+ "libstrip-1b" \
+ "C" \
+ "tmpdir/strip-1a-s.o" \
+ ] \
+ [list \
+ "Build strip-1c (libstrip-1a.a)" \
+ "" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1b.c } \
+ {} \
+ "libstrip-1c" \
+ "C" \
+ "tmpdir/libstrip-1a.a" \
+ ] \
+ [list \
+ "Build strip-1d (libstrip-1a-s.a)" \
+ "" \
+ "-O2 -flto $lto_no_fat" \
+ { strip-1b.c } \
+ {} \
+ "libstrip-1d" \
+ "C" \
+ "tmpdir/libstrip-1a-s.a" \
+ ] \
+ [list \
+ "Build strip-1e (strip-1a-fat-s.o)" \
+ "" \
+ "-O2 -flto $lto_fat" \
+ { strip-1b-fat.c } \
+ {} \
+ "libstrip-1e" \
+ "C" \
+ "tmpdir/strip-1a-fat-s.o" \
+ ] \
+ [list \
+ "Build strip-1f (libstrip-1a-fat-s.a)" \
+ "" \
+ "-O2 -flto $lto_fat" \
+ { strip-1b-fat.c } \
+ {} \
+ "libstrip-1f" \
+ "C" \
+ "tmpdir/libstrip-1a-fat-s.a" \
+ ] \
+ [list \
+ "Build strip-1g (strip-1b-fat-s.o)" \
+ "" \
+ "-O2 -flto $lto_fat" \
+ { strip-1b-fat.c } \
+ {} \
+ "libstrip-1g" \
+ "C" \
+ "tmpdir/strip-1b-fat-s.o" \
+ ] \
+ [list \
+ "Build strip-1h (libstrip-1b-fat-s.a)" \
+ "" \
+ "-O2 -flto $lto_fat" \
+ { strip-1b-fat.c } \
+ {} \
+ "libstrip-1h" \
+ "C" \
+ "tmpdir/libstrip-1b-fat-s.a" \
+ ] \
+]
diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp
index 3a56fb5..f0d0954 100644
--- a/ld/testsuite/ld-plugin/lto.exp
+++ b/ld/testsuite/ld-plugin/lto.exp
@@ -1158,9 +1158,8 @@ remote_exec host "mv" "tmpdir/dump tmpdir/lto-5.o"
run_dump_test "lto-10r"
remote_exec host "mv" "tmpdir/dump tmpdir/lto-10.o"
set testname "nm mixed object"
-set lto_plugin [string trim [run_host_cmd "$CC_FOR_TARGET" "-print-prog-name=liblto_plugin.so"]]
-if { [ regexp "liblto_plugin.so" $lto_plugin ] } {
- set exec_output [run_host_cmd "$NM" "--plugin $lto_plugin tmpdir/lto-10.o"]
+if { $plug_opt != "" } {
+ set exec_output [run_host_cmd "$NM" "$plug_opt tmpdir/lto-10.o"]
if { [ regexp "(D|T) main" $exec_output ] } {
pass $testname
} else {
diff --git a/ld/testsuite/ld-plugin/strip-1a-fat.c b/ld/testsuite/ld-plugin/strip-1a-fat.c
new file mode 100644
index 0000000..03b2a5c
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1a-fat.c
@@ -0,0 +1 @@
+#include "strip-1a.c"
diff --git a/ld/testsuite/ld-plugin/strip-1a-fat.rd b/ld/testsuite/ld-plugin/strip-1a-fat.rd
new file mode 100644
index 0000000..aefe1c5
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1a-fat.rd
@@ -0,0 +1,6 @@
+#failif
+#...
+Section Headers:
+#...
+ \[[ 0-9]+\] \.gnu.lto_.*
+#...
diff --git a/ld/testsuite/ld-plugin/strip-1a.c b/ld/testsuite/ld-plugin/strip-1a.c
new file mode 100644
index 0000000..d84af20
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1a.c
@@ -0,0 +1,4 @@
+extern void foo2(void);
+extern void foo3(void);
+void foo1(void) { foo3(); }
+int main(void) { foo2(); }
diff --git a/ld/testsuite/ld-plugin/strip-1b-fat.c b/ld/testsuite/ld-plugin/strip-1b-fat.c
new file mode 100644
index 0000000..1a2e4d2
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1b-fat.c
@@ -0,0 +1 @@
+#include "strip-1b.c"
diff --git a/ld/testsuite/ld-plugin/strip-1b-fat.rd b/ld/testsuite/ld-plugin/strip-1b-fat.rd
new file mode 100644
index 0000000..e3a266f
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1b-fat.rd
@@ -0,0 +1,5 @@
+#...
+Section Headers:
+#...
+ \[[ 0-9]+\] \.gnu.lto_.*
+#pass
diff --git a/ld/testsuite/ld-plugin/strip-1b.c b/ld/testsuite/ld-plugin/strip-1b.c
new file mode 100644
index 0000000..967872a
--- /dev/null
+++ b/ld/testsuite/ld-plugin/strip-1b.c
@@ -0,0 +1,3 @@
+extern void foo1(void);
+void foo2(void) { foo1(); }
+void foo3(void) {}
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 9615271..119410b 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -860,14 +860,15 @@ proc run_ld_link_exec_tests { ldtests args } {
}
# List contains test-items with 3 items followed by 2 lists, one item and
-# one optional item:
+# 2 optional items:
# 0:name
-# 1:ld or ar options
+# 1:leading ld or ar options
# 2:compile options
# 3:filenames of source files
# 4:action and options.
# 5:name of output file
# 6:language (optional)
+# 7:trailing ld options (optional), placed after object files
#
# Actions:
# objdump: Apply objdump options on result. Compare with regex (last arg).
@@ -899,6 +900,7 @@ proc run_cc_link_tests { ldtests } {
set actions [lindex $testitem 4]
set binfile tmpdir/[lindex $testitem 5]
set lang [lindex $testitem 6]
+ set trailing_ldflags [lindex $testitem 7]
set objfiles {}
set is_unresolved 0
set failed 0
@@ -927,6 +929,7 @@ proc run_cc_link_tests { ldtests } {
#verbose -log "actions is $actions"
#verbose -log "binfile is $binfile"
#verbose -log "lang is $lang"
+ #verbose -log "trailing_ldflags is $trailing_ldflags"
foreach actionlist $actions {
set action [lindex $actionlist 0]
@@ -1006,7 +1009,7 @@ proc run_cc_link_tests { ldtests } {
untested $testname
continue
}
- ld_link $cc_cmd $binfile "-L$srcdir/$subdir $ldflags $objfiles"
+ ld_link $cc_cmd $binfile "-L$srcdir/$subdir $ldflags $objfiles $trailing_ldflags"
set ld_output "$exec_output"
if { $check_ld(source) == "regexp" } then {
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 3a52251..3bb93a9 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -5214,6 +5214,8 @@ const aarch64_sys_ins_reg aarch64_sys_regs_dc[] =
{ "cvac", CPENS (3, C7, C10, 1), F_HASXT, AARCH64_NO_FEATURES },
{ "cgvac", CPENS (3, C7, C10, 3), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
{ "cgdvac", CPENS (3, C7, C10, 5), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
+ { "cvaoc", CPENS (3, C7, C11, 0), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (V9_5A) },
+ { "cgdvaoc", CPENS (3, C7, C11, 7), F_HASXT | F_ARCHEXT, AARCH64_FEATURES (2, V9_5A, MEMTAG) },
{ "csw", CPENS (0, C7, C10, 2), F_HASXT, AARCH64_NO_FEATURES },
{ "cgsw", CPENS (0, C7, C10, 4), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
{ "cgdsw", CPENS (0, C7, C10, 6), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
@@ -5230,6 +5232,8 @@ const aarch64_sys_ins_reg aarch64_sys_regs_dc[] =
{ "cisw", CPENS (0, C7, C14, 2), F_HASXT, AARCH64_NO_FEATURES },
{ "cigsw", CPENS (0, C7, C14, 4), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
{ "cigdsw", CPENS (0, C7, C14, 6), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (MEMTAG) },
+ { "civaoc", CPENS (3, C7, C15, 0), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (V9_5A) },
+ { "cigdvaoc", CPENS (3, C7, C15, 7), F_HASXT | F_ARCHEXT, AARCH64_FEATURES (2, V9_5A, MEMTAG) },
{ "cipae", CPENS (4, C7, C14, 0), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (V8_7A) },
{ "cigdpae", CPENS (4, C7, C14, 7), F_HASXT | F_ARCHEXT, AARCH64_FEATURE (V8_7A) },
{ "cipapa", CPENS (6, C7, C14, 1), F_HASXT, AARCH64_NO_FEATURES },
diff --git a/opcodes/aarch64-sys-regs.def b/opcodes/aarch64-sys-regs.def
index c1b07c7..9713ff0 100644
--- a/opcodes/aarch64-sys-regs.def
+++ b/opcodes/aarch64-sys-regs.def
@@ -437,6 +437,7 @@
SYSREG ("gcscr_el3", CPENC (3,6,2,5,0), F_ARCHEXT, AARCH64_FEATURE (GCS))
SYSREG ("gcr_el1", CPENC (3,0,1,0,6), F_ARCHEXT, AARCH64_FEATURE (MEMTAG))
SYSREG ("gmid_el1", CPENC (3,1,0,0,4), F_REG_READ|F_ARCHEXT, AARCH64_FEATURE (MEMTAG))
+ SYSREG ("gpcbw_el3", CPENC (3,6,2,1,5), F_ARCHEXT, AARCH64_FEATURE (V9_5A))
SYSREG ("gpccr_el3", CPENC (3,6,2,1,6), 0, AARCH64_NO_FEATURES)
SYSREG ("gptbr_el3", CPENC (3,6,2,1,4), 0, AARCH64_NO_FEATURES)
SYSREG ("hacr_el2", CPENC (3,4,1,1,7), 0, AARCH64_NO_FEATURES)
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 77c3dc8..f43e1e3 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -4642,14 +4642,14 @@ const struct aarch64_opcode aarch64_opcode_table[] =
PREDRES_INSN ("cpp", 0xd50b73e0, 0xffffffe0, ic_system, OP2 (SYSREG_SR, Rt), QL_SRC_X, F_ALIAS),
PREDRES2_INSN ("cosp", 0xd50b73c0, 0xffffffe0, ic_system, OP2 (SYSREG_SR, Rt), QL_SRC_X, F_ALIAS),
BRBE_INSN ("brb", 0xd5097280, 0xffffffc0, OP2 (BRBOP, Rt_IN_SYS_ALIASES), QL_IMM_NIL_NIL, F_ALIAS | F_OPD1_OPT | F_DEFAULT (0x1F)),
- /* Armv8.4-a flag setting instruction, However this encoding has an encoding clash with the msr
- below it. Usually we can resolve this by setting an alias condition on the flags, however that
- depends on the disassembly masks to be able to quickly find the alias. The problem is the
- cfinv instruction has no arguments, so all bits are set in the mask. Which means it will
- potentially alias with too many instructions and so the tree can't be constructed. As a work
- around we just place cfinv before msr. This means the order between these two shouldn't be
- changed. */
FLAGM_INSN ("cfinv", 0xd500401f, 0xffffffff, ic_system, OP0 (), {}, 0),
+ /* This msr entry has a lot of aliases, and some of these (such as "hint")
+ have their own (recursive) aliases. We currently use a flat alias
+ structure, so to avoid creating an excessively long list of aliases for
+ the entire msr space we instead handle the top level of disambiguation
+ outside the alias infrastructure. This requires that all of the top-level
+ aliases of msr must appear earlier in the opcode table, since normal
+ (non-alias) disassembly is done on a "first match" basis. */
CORE_INSN ("msr", 0xd5000000, 0xffe00000, ic_system, 0, OP2 (SYSREG, Rt), QL_SRC_X, F_SYS_WRITE),
CORE_INSN ("sysl",0xd5280000, 0xfff80000, ic_system, 0, OP5 (Rt, UIMM3_OP1, CRn, CRm, UIMM3_OP2), QL_SYSL, 0),
CORE_INSN ("mrs", 0xd5200000, 0xffe00000, ic_system, 0, OP2 (Rt, SYSREG), QL_DST_X, F_SYS_READ),