aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/archive.c10
-rw-r--r--bfd/bfd-in2.h10
-rw-r--r--bfd/bfd.c3
-rw-r--r--bfd/format.c144
-rw-r--r--bfd/plugin.c24
-rw-r--r--bfd/plugin.h1
-rw-r--r--bfd/version.h2
-rw-r--r--binutils/nm.c9
-rw-r--r--binutils/objcopy.c57
-rw-r--r--gdb/arm-linux-tdep.c5
-rw-r--r--gdb/breakpoint.c25
-rw-r--r--gdb/breakpoint.h8
-rw-r--r--gdb/compile/compile.c1
-rw-r--r--gdb/debuginfod-support.c1
-rw-r--r--gdb/gdbarch-gen.h12
-rw-r--r--gdb/gdbarch_components.py12
-rw-r--r--gdb/infrun.c19
-rw-r--r--gdb/record-full.c4
-rw-r--r--gdb/run-on-main-thread.c1
-rw-r--r--gdb/testsuite/gdb.base/style.exp16
-rw-r--r--gdb/testsuite/lib/gdb-utils.exp4
-rw-r--r--gdb/testsuite/lib/gdb.exp4
-rw-r--r--gdb/top.c1
-rw-r--r--gdb/tui/tui-io.c8
-rw-r--r--gdb/ui-style.c26
-rw-r--r--gdb/ui-style.h36
-rw-r--r--gdb/unittests/style-selftests.c32
-rw-r--r--gdb/value.c1
-rw-r--r--gdbsupport/common-defs.h1
-rw-r--r--ld/testsuite/ld-plugin/lto-binutils.exp175
-rw-r--r--ld/testsuite/ld-plugin/pr33246.c4
31 files changed, 478 insertions, 178 deletions
diff --git a/bfd/archive.c b/bfd/archive.c
index c61d4b1..697b2ed 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -141,6 +141,10 @@ SUBSECTION
#include "hashtab.h"
#include "filenames.h"
#include "bfdlink.h"
+#if BFD_SUPPORTS_PLUGINS
+#include "plugin-api.h"
+#include "plugin.h"
+#endif
#ifndef errno
extern int errno;
@@ -2343,6 +2347,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
long src_count;
if (bfd_get_lto_type (current) == lto_slim_ir_object
+#if BFD_SUPPORTS_PLUGINS
+ && !bfd_plugin_target_p (current->xvec)
+#endif
&& report_plugin_err)
{
report_plugin_err = false;
@@ -2400,6 +2407,9 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
if (bfd_lto_slim_symbol_p (current,
syms[src_count]->name)
+#if BFD_SUPPORTS_PLUGINS
+ && !bfd_plugin_target_p (current->xvec)
+#endif
&& report_plugin_err)
{
report_plugin_err = false;
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 2ff3e93..12512a3 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2131,6 +2131,9 @@ struct bfd
/* Set if this is the linker input BFD. */
unsigned int is_linker_input : 1;
+ /* Set if this is the strip input BFD. */
+ unsigned int is_strip_input : 1;
+
/* If this is an input for a compiler plug-in library. */
ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
@@ -2903,15 +2906,8 @@ bool generic_core_file_matches_executable_p
(bfd *core_bfd, bfd *exec_bfd);
/* Extracted from format.c. */
-bool bfd_check_format_lto (bfd *abfd, bfd_format format,
- bool lto_sections_removed);
-
bool bfd_check_format (bfd *abfd, bfd_format format);
-bool bfd_check_format_matches_lto
- (bfd *abfd, bfd_format format, char ***matching,
- bool lto_sections_removed);
-
bool bfd_check_format_matches
(bfd *abfd, bfd_format format, char ***matching);
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 858ab5c..4aded68 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -296,6 +296,9 @@ CODE_FRAGMENT
. {* Set if this is the linker input BFD. *}
. unsigned int is_linker_input : 1;
.
+. {* Set if this is the strip input BFD. *}
+. unsigned int is_strip_input : 1;
+.
. {* If this is an input for a compiler plug-in library. *}
. ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
.
diff --git a/bfd/format.c b/bfd/format.c
index f3a0774..bd9fa8d 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -56,19 +56,16 @@ extern const size_t _bfd_target_vector_entries;
/*
FUNCTION
- bfd_check_format_lto
+ bfd_check_format
SYNOPSIS
- bool bfd_check_format_lto (bfd *abfd, bfd_format format,
- bool lto_sections_removed);
+ bool bfd_check_format (bfd *abfd, bfd_format format);
DESCRIPTION
Verify if the file attached to the BFD @var{abfd} is compatible
with the format @var{format} (i.e., one of <<bfd_object>>,
<<bfd_archive>> or <<bfd_core>>).
- If LTO_SECTION_REMOVED is true, ignore plugin target.
-
If the BFD has been set to a specific target before the
call, only the named target and format combination is
checked. If the target has not been set, or has been set to
@@ -103,30 +100,9 @@ DESCRIPTION
*/
bool
-bfd_check_format_lto (bfd *abfd, bfd_format format,
- bool lto_sections_removed)
-{
- return bfd_check_format_matches_lto (abfd, format, NULL,
- lto_sections_removed);
-}
-
-
-/*
-FUNCTION
- bfd_check_format
-
-SYNOPSIS
- bool bfd_check_format (bfd *abfd, bfd_format format);
-
-DESCRIPTION
- Similar to bfd_check_format_plugin, except plugin target isn't
- ignored.
-*/
-
-bool
bfd_check_format (bfd *abfd, bfd_format format)
{
- return bfd_check_format_matches_lto (abfd, format, NULL, false);
+ return bfd_check_format_matches (abfd, format, NULL);
}
struct bfd_preserve
@@ -413,6 +389,11 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
abfd->object_only_section = sec;
break;
}
+ else if (strcmp (sec->name, ".llvm.lto") == 0)
+ {
+ type = lto_fat_ir_object;
+ break;
+ }
else if (lsection.major_version == 0
&& startswith (sec->name, ".gnu.lto_.lto.")
&& bfd_get_section_contents (abfd, sec, &lsection, 0,
@@ -431,36 +412,32 @@ bfd_set_lto_type (bfd *abfd ATTRIBUTE_UNUSED)
/*
FUNCTION
- bfd_check_format_matches_lto
+ bfd_check_format_matches
SYNOPSIS
- bool bfd_check_format_matches_lto
- (bfd *abfd, bfd_format format, char ***matching,
- bool lto_sections_removed);
+ bool bfd_check_format_matches
+ (bfd *abfd, bfd_format format, char ***matching);
DESCRIPTION
Like <<bfd_check_format>>, except when it returns FALSE with
- <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that
- case, if @var{matching} is not NULL, it will be filled in with
- a NULL-terminated list of the names of the formats that matched,
- allocated with <<malloc>>.
+ <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>.
+ In that case, if @var{matching} is not NULL, it will be filled
+ in with a NULL-terminated list of the names of the formats
+ that matched, allocated with <<malloc>>.
Then the user may choose a format and try again.
When done with the list that @var{matching} points to, the caller
should free it.
-
- If LTO_SECTION_REMOVED is true, ignore plugin target.
*/
bool
-bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
- char ***matching,
- bool lto_sections_removed ATTRIBUTE_UNUSED)
+bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
{
extern const bfd_target binary_vec;
const bfd_target * const *target;
const bfd_target **matching_vector = NULL;
const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ;
+ const bfd_target *fail_targ;
int match_count, best_count, best_match;
int ar_match_index;
unsigned int initial_section_id = _bfd_section_id;
@@ -481,10 +458,7 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
}
if (abfd->format != bfd_unknown)
- {
- bfd_set_lto_type (abfd);
- return abfd->format == format;
- }
+ return abfd->format == format;
if (matching != NULL || *bfd_associated_vector != NULL)
{
@@ -524,20 +498,34 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
if (!bfd_preserve_save (abfd, &preserve, NULL))
goto err_ret;
- /* If the target type was explicitly specified, just check that target.
- If LTO_SECTION_REMOVED is true, don't match the plugin target. */
+ /* If the target type was explicitly specified, just check that target. */
+ fail_targ = NULL;
if (!abfd->target_defaulted
#if BFD_SUPPORTS_PLUGINS
- && (!lto_sections_removed || !bfd_plugin_target_p (abfd->xvec))
+ && !(abfd->plugin_format == bfd_plugin_no
+ && bfd_plugin_target_p (save_targ))
#endif
- )
+ )
{
if (bfd_seek (abfd, 0, SEEK_SET) != 0) /* rewind! */
goto err_ret;
cleanup = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
- if (cleanup)
+ /* When called from strip, don't treat archive member nor
+ standalone fat IR object as an IR object. For archive
+ member, it will be copied as an unknown object if the
+ plugin target is in use or it is a slim IR object. For
+ standalone fat IR object, it will be copied as non-IR
+ object. */
+ if (cleanup
+#if BFD_SUPPORTS_PLUGINS
+ && (!abfd->is_strip_input
+ || !bfd_plugin_target_p (abfd->xvec)
+ || (abfd->lto_type != lto_fat_ir_object
+ && abfd->my_archive == NULL))
+#endif
+ )
goto ok_ret;
/* For a long time the code has dropped through to check all
@@ -554,10 +542,10 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
target. */
if (format == bfd_archive && save_targ == &binary_vec)
goto err_unrecog;
+ fail_targ = save_targ;
}
- /* Since the target type was defaulted, check them all in the hope
- that one will be uniquely recognized. */
+ /* Check all targets in the hope that one will be recognized. */
right_targ = NULL;
ar_right_targ = NULL;
match_targ = NULL;
@@ -571,26 +559,26 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
void **high_water;
/* The binary target matches anything, so don't return it when
- searching. Don't match the plugin target if we have another
- alternative since we want to properly set the input format
- before allowing a plugin to claim the file. Also, don't
- check the default target twice. If LTO_SECTION_REMOVED is
- true, don't match the plugin target. */
+ searching. Also, don't check the current target twice when
+ it has failed already.
+ Don't match the plugin target during linking if we have
+ another alternative since we want to properly set the input
+ format before allowing a plugin to claim the file.
+ Also as an optimisation don't match the plugin target when
+ abfd->plugin_format is set to bfd_plugin_no. (This occurs
+ when LTO sections have been stripped or when we have a
+ recursive call here from the plugin object_p via
+ bfd_plugin_get_symbols_in_object_only.) */
if (*target == &binary_vec
+ || *target == fail_targ
#if BFD_SUPPORTS_PLUGINS
- || ((lto_sections_removed || match_count != 0)
+ || (((abfd->is_linker_input && match_count != 0)
+ || abfd->plugin_format == bfd_plugin_no)
&& bfd_plugin_target_p (*target))
#endif
- || (!abfd->target_defaulted && *target == save_targ))
+ )
continue;
-#if BFD_SUPPORTS_PLUGINS
- /* If the plugin target is explicitly specified when a BFD file
- is opened, don't check it twice. */
- if (bfd_plugin_specified_p () && bfd_plugin_target_p (*target))
- continue;
-#endif
-
/* If we already tried a match, the bfd is modified and may
have sections attached, which will confuse the next
_bfd_check_format call. */
@@ -833,32 +821,6 @@ bfd_check_format_matches_lto (bfd *abfd, bfd_format format,
/*
FUNCTION
- bfd_check_format_matches
-
-SYNOPSIS
- bool bfd_check_format_matches
- (bfd *abfd, bfd_format format, char ***matching);
-
-DESCRIPTION
- Like <<bfd_check_format>>, except when it returns FALSE with
- <<bfd_errno>> set to <<bfd_error_file_ambiguously_recognized>>. In that
- case, if @var{matching} is not NULL, it will be filled in with
- a NULL-terminated list of the names of the formats that matched,
- allocated with <<malloc>>.
- Then the user may choose a format and try again.
-
- When done with the list that @var{matching} points to, the caller
- should free it.
-*/
-
-bool
-bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
-{
- return bfd_check_format_matches_lto (abfd, format, matching, false);
-}
-
-/*
-FUNCTION
bfd_set_format
SYNOPSIS
diff --git a/bfd/plugin.c b/bfd/plugin.c
index 1c72b74..43ca444 100644
--- a/bfd/plugin.c
+++ b/bfd/plugin.c
@@ -196,16 +196,23 @@ bfd_plugin_get_symbols_in_object_only (bfd *abfd)
abfd->filename, bfd_errmsg (bfd_get_error ()));
return;
}
- else if (!bfd_check_format (nbfd, bfd_object))
+ /* Prevent this recursive call into bfd_check_format from
+ attempting to load the plugin again while it is running. */
+ nbfd->plugin_format = bfd_plugin_no;
+ if (!bfd_check_format (nbfd, bfd_object))
{
/* There is no object only section if it isn't a bfd_object
file. */
bfd_close (nbfd);
return;
}
+
+ /* Copy LTO type derived from input sections. */
+ abfd->lto_type = nbfd->lto_type;
}
else
{
+ BFD_ASSERT (abfd->plugin_format == bfd_plugin_no);
if (!bfd_check_format (abfd, bfd_object))
{
(*_bfd_error_handler)
@@ -239,6 +246,9 @@ bfd_plugin_get_symbols_in_object_only (bfd *abfd)
/* Open the file containing object only section. */
nbfd = bfd_openr (object_only_file, NULL);
+ /* Prevent this recursive call into bfd_check_format from
+ attempting to load the plugin again while it is running. */
+ nbfd->plugin_format = bfd_plugin_no;
if (!bfd_check_format (nbfd, bfd_object))
{
(*_bfd_error_handler)
@@ -598,6 +608,10 @@ try_load_plugin (const char *pname,
if (status != LDPS_OK)
goto short_circuit;
+ /* Setting bfd_plugin_no here prevents recursive calls into
+ bfd_check_format from within the plugin (unless the plugin opens
+ another bfd.) Attempting to load the plugin again while it is
+ running is *not* a good idea. */
abfd->plugin_format = bfd_plugin_no;
if (!current_plugin->claim_file)
@@ -627,14 +641,6 @@ bfd_plugin_set_plugin (const char *p)
plugin_name = p;
}
-/* Return TRUE if a plugin library is used. */
-
-bool
-bfd_plugin_specified_p (void)
-{
- return plugin_list != NULL;
-}
-
/* Return TRUE if ABFD can be claimed by linker LTO plugin. */
bool
diff --git a/bfd/plugin.h b/bfd/plugin.h
index f61e616..6acb5fa 100644
--- a/bfd/plugin.h
+++ b/bfd/plugin.h
@@ -25,7 +25,6 @@ void bfd_plugin_set_program_name (const char *);
int bfd_plugin_open_input (bfd *, struct ld_plugin_input_file *);
void bfd_plugin_set_plugin (const char *);
bool bfd_plugin_target_p (const bfd_target *);
-bool bfd_plugin_specified_p (void);
bool bfd_link_plugin_object_p (bfd *);
void register_ld_plugin_object_p (bfd_cleanup (*object_p) (bfd *, bool));
void bfd_plugin_close_file_descriptor (bfd *, int);
diff --git a/bfd/version.h b/bfd/version.h
index 882d0b0..b5f5582 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 20250805
+#define BFD_VERSION_DATE 20250806
#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/nm.c b/binutils/nm.c
index a5d5631..d44083d 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -802,6 +802,9 @@ filter_symbols (bfd *abfd, bool is_dynamic, void *minisyms,
continue;
if (bfd_lto_slim_symbol_p (abfd, sym->name)
+#if BFD_SUPPORTS_PLUGINS
+ && !bfd_plugin_target_p (abfd->xvec)
+#endif
&& report_plugin_err)
{
report_plugin_err = false;
@@ -1484,7 +1487,11 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
/* lto_type is set to lto_non_ir_object when a bfd is loaded with a
compiler LTO plugin. */
- if (bfd_get_lto_type (abfd) == lto_slim_ir_object)
+ if (bfd_get_lto_type (abfd) == lto_slim_ir_object
+#if BFD_SUPPORTS_PLUGINS
+ && !bfd_plugin_target_p (abfd->xvec)
+#endif
+ )
{
report_plugin_err = false;
non_fatal (_("%s: plugin needed to handle lto object"),
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index 5774711..3404bec 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -170,6 +170,8 @@ static bool sections_removed;
#if BFD_SUPPORTS_PLUGINS
/* TRUE if all GCC LTO sections are to be removed. */
static bool lto_sections_removed;
+#else
+#define lto_sections_removed false
#endif
/* TRUE if only some sections are to be copied. */
@@ -3687,6 +3689,8 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
bool ok_object;
const char *element_name;
+ this_element->is_strip_input = 1;
+
element_name = bfd_get_filename (this_element);
/* PR binutils/17533: Do not allow directory traversal
outside of the current directory tree by archive members. */
@@ -3745,11 +3749,10 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
#if BFD_SUPPORTS_PLUGINS
/* Ignore plugin target if all LTO sections should be removed. */
- ok_object = bfd_check_format_lto (this_element, bfd_object,
- lto_sections_removed);
-#else
- ok_object = bfd_check_format (this_element, bfd_object);
+ if (lto_sections_removed)
+ this_element->plugin_format = bfd_plugin_no;
#endif
+ ok_object = bfd_check_format (this_element, bfd_object);
/* PR binutils/3110: Cope with archives
containing multiple target types. */
@@ -3768,7 +3771,9 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
#if BFD_SUPPORTS_PLUGINS
/* Copy LTO IR file as unknown object. */
- if (bfd_plugin_target_p (this_element->xvec))
+ if ((!lto_sections_removed
+ && this_element->lto_type == lto_slim_ir_object)
+ || bfd_plugin_target_p (this_element->xvec))
ok_object = false;
else
#endif
@@ -3863,6 +3868,25 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
return ok;
}
+static bool
+check_format_object (bfd *ibfd, char ***obj_matching,
+ bool no_plugins ATTRIBUTE_UNUSED)
+{
+#if BFD_SUPPORTS_PLUGINS
+ /* Ignore plugin target first if all LTO sections should be
+ removed. Try with plugin target next if ignoring plugin
+ target fails to match the format. */
+ if (no_plugins && ibfd->plugin_format == bfd_plugin_unknown)
+ {
+ ibfd->plugin_format = bfd_plugin_no;
+ if (bfd_check_format_matches (ibfd, bfd_object, obj_matching))
+ return true;
+ ibfd->plugin_format = bfd_plugin_unknown;
+ }
+#endif
+ return bfd_check_format_matches (ibfd, bfd_object, obj_matching);
+}
+
/* The top-level control. */
static void
@@ -3946,6 +3970,8 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
break;
}
+ ibfd->is_strip_input = 1;
+
if (bfd_check_format (ibfd, bfd_archive))
{
bool force_output_target;
@@ -3988,21 +4014,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd,
input_arch, target_defaulted))
status = 1;
}
- else if (
-#if BFD_SUPPORTS_PLUGINS
- /* Ignore plugin target first if all LTO sections should be
- removed. Try with plugin target next if ignoring plugin
- target fails to match the format. */
- bfd_check_format_matches_lto (ibfd, bfd_object, &obj_matching,
- lto_sections_removed)
- || (lto_sections_removed
- && bfd_check_format_matches_lto (ibfd, bfd_object,
- &obj_matching, false))
-#else
- bfd_check_format_matches_lto (ibfd, bfd_object, &obj_matching,
- false)
-#endif
- )
+ else if (check_format_object (ibfd, &obj_matching, lto_sections_removed))
{
bfd *obfd;
do_copy:
@@ -5066,6 +5078,11 @@ strip_main (int argc, char *argv[])
SECTION_CONTEXT_REMOVE)
|| !!find_section_list (".llvm.lto", false,
SECTION_CONTEXT_REMOVE));
+ /* NB: Must keep .gnu.debuglto_* sections unless all GCC LTO sections
+ will be removed to avoid undefined references to symbols in GCC LTO
+ debug sections. */
+ if (!lto_sections_removed)
+ find_section_list (".gnu.debuglto_*", true, SECTION_CONTEXT_KEEP);
#endif
i = optind;
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 2f034af..08526d8 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -960,6 +960,11 @@ arm_linux_software_single_step (struct regcache *regcache)
struct gdbarch *gdbarch = regcache->arch ();
struct arm_get_next_pcs next_pcs_ctx;
+ /* If the target does have hardware single step, GDB doesn't have
+ to bother software single step. */
+ if (target_can_do_single_step () == 1)
+ return {};
+
arm_get_next_pcs_ctor (&next_pcs_ctx,
&arm_linux_get_next_pcs_ops,
gdbarch_byte_order (gdbarch),
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f795d7b..d704ad1 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -13998,26 +13998,11 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch,
update_global_location_list (UGLL_INSERT);
}
-/* Try to setup for software single stepping. Return true if
- target_resume() should use hardware single step.
+/* Insert single step breakpoints according to the current state. */
- GDBARCH is the current gdbarch. */
-
-bool
-maybe_software_singlestep (struct gdbarch *gdbarch)
+int
+insert_single_step_breakpoints (struct gdbarch *gdbarch)
{
- if (execution_direction != EXEC_FORWARD)
- return true;
-
- if (target_can_do_single_step () == 1)
- {
- /* The target definitely has hardware single step. */
- return true;
- }
-
- if (!gdbarch_software_single_step_p (gdbarch))
- return true;
-
regcache *regcache = get_thread_regcache (inferior_thread ());
std::vector<CORE_ADDR> next_pcs;
@@ -14031,10 +14016,10 @@ maybe_software_singlestep (struct gdbarch *gdbarch)
for (CORE_ADDR pc : next_pcs)
insert_single_step_breakpoint (gdbarch, aspace, pc);
- return false;
+ return 1;
}
else
- return true;
+ return 0;
}
/* See breakpoint.h. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e9201bc..9341112 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1884,10 +1884,10 @@ extern void insert_single_step_breakpoint (struct gdbarch *,
const address_space *,
CORE_ADDR);
-/* Try to setup for software single stepping. Return true if
- target_resume() should use hardware single step. GDBARCH is the
- current gdbarch. */
-extern bool maybe_software_singlestep (struct gdbarch *);
+/* Insert all software single step breakpoints for the current frame.
+ Return true if any software single step breakpoints are inserted,
+ otherwise, return false. */
+extern int insert_single_step_breakpoints (struct gdbarch *);
/* Check whether any hardware watchpoints have triggered or not,
according to the target, and record it in each watchpoint's
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 229e155..5d81ec1 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -45,6 +45,7 @@
#include "gdbsupport/pathstuff.h"
#include "gdbsupport/scoped_ignore_signal.h"
#include "gdbsupport/buildargv.h"
+#include "gdbsupport/cleanups.h"
/* Hold "compile" commands. */
diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
index 8f28fd5..e99c13b 100644
--- a/gdb/debuginfod-support.c
+++ b/gdb/debuginfod-support.c
@@ -18,6 +18,7 @@
#include "diagnostics.h"
#include <errno.h>
+#include "gdbsupport/cleanups.h"
#include "gdbsupport/scoped_fd.h"
#include "debuginfod-support.h"
#include <optional>
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 1e51081..281b97b 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -776,10 +776,16 @@ extern void set_gdbarch_get_memtag (struct gdbarch *gdbarch, gdbarch_get_memtag_
extern CORE_ADDR gdbarch_memtag_granule_size (struct gdbarch *gdbarch);
extern void set_gdbarch_memtag_granule_size (struct gdbarch *gdbarch, CORE_ADDR memtag_granule_size);
-/* Return a vector of addresses at which the software single step
- breakpoints should be inserted. An empty vector means software single
- step is not used.
+/* FIXME/cagney/2001-01-18: This should be split in two. A target method that
+ indicates if the target needs software single step. An ISA method to
+ implement it.
+ FIXME/cagney/2001-01-18: The logic is backwards. It should be asking if the
+ target can single step. If not, then implement single step using breakpoints.
+
+ Return a vector of addresses on which the software single step
+ breakpoints should be inserted. NULL means software single step is
+ not used.
Multiple breakpoints may be inserted for some instructions such as
conditional branch. However, each implementation must always evaluate
the condition and only put the breakpoint at the branch destination if
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index 55df102..91c867e 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -1378,10 +1378,16 @@ For a non-zero value, this represents the number of bytes of memory per tag.
Function(
comment="""
-Return a vector of addresses at which the software single step
-breakpoints should be inserted. An empty vector means software single
-step is not used.
+FIXME/cagney/2001-01-18: This should be split in two. A target method that
+indicates if the target needs software single step. An ISA method to
+implement it.
+FIXME/cagney/2001-01-18: The logic is backwards. It should be asking if the
+target can single step. If not, then implement single step using breakpoints.
+
+Return a vector of addresses on which the software single step
+breakpoints should be inserted. NULL means software single step is
+not used.
Multiple breakpoints may be inserted for some instructions such as
conditional branch. However, each implementation must always evaluate
the condition and only put the breakpoint at the branch destination if
diff --git a/gdb/infrun.c b/gdb/infrun.c
index e0e9ffa..9d3e1b7 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -93,6 +93,8 @@ static void insert_step_resume_breakpoint_at_caller (const frame_info_ptr &);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
+static bool maybe_software_singlestep (struct gdbarch *gdbarch);
+
static void resume (gdb_signal sig);
static void wait_for_inferior (inferior *inf);
@@ -2357,6 +2359,23 @@ set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c)
process. */
bool sched_multi = false;
+/* Try to setup for software single stepping. Return true if target_resume()
+ should use hardware single step.
+
+ GDBARCH the current gdbarch. */
+
+static bool
+maybe_software_singlestep (struct gdbarch *gdbarch)
+{
+ bool hw_step = true;
+
+ if (execution_direction == EXEC_FORWARD
+ && gdbarch_software_single_step_p (gdbarch))
+ hw_step = !insert_single_step_breakpoints (gdbarch);
+
+ return hw_step;
+}
+
/* See infrun.h. */
ptid_t
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 7d4ef87..7e3da27 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1105,7 +1105,7 @@ record_full_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
record_full_resume_step = 1;
}
else
- step = maybe_software_singlestep (gdbarch);
+ step = !insert_single_step_breakpoints (gdbarch);
}
}
@@ -1277,7 +1277,7 @@ record_full_wait_1 (struct target_ops *ops,
};
reinit_frame_cache ();
- step = maybe_software_singlestep (gdbarch);
+ step = !insert_single_step_breakpoints (gdbarch);
}
if (record_debug)
diff --git a/gdb/run-on-main-thread.c b/gdb/run-on-main-thread.c
index 30b0928..bf53163 100644
--- a/gdb/run-on-main-thread.c
+++ b/gdb/run-on-main-thread.c
@@ -22,6 +22,7 @@
#include <thread>
#include <mutex>
#endif
+#include "gdbsupport/cleanups.h"
#include "gdbsupport/event-loop.h"
/* The serial event used when posting runnables. */
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index 47efb64..a6c18d3 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -323,10 +323,10 @@ proc run_style_tests { } {
gdb_test_no_output "set style version background 255"
gdb_test_no_output "set style version foreground #FED210"
gdb_test "show style version background" \
- "The \033\\\[38;2;254;210;16;48;5;255;22;27m.*\".*version.*\".*style.*\033\\\[m background color is: 255" \
+ "The \033\\\[38;2;254;210;16;48;5;255;22;23;24;27m.*\".*version.*\".*style.*\033\\\[m background color is: 255" \
"Version's 256-color background style"
gdb_test "show style version foreground" \
- "The \033\\\[38;2;254;210;16;48;5;255;22;27m.*\".*version.*\".*style.*\033\\\[m foreground color is: #FED210" \
+ "The \033\\\[38;2;254;210;16;48;5;255;22;23;24;27m.*\".*version.*\".*style.*\033\\\[m foreground color is: #FED210" \
"Version's TrueColor foreground style"
}
@@ -782,7 +782,7 @@ proc test_pagination_cmd_after_quit_styling {} {
-re "^apropos time\r\n" {
exp_continue
}
- -re "^\033\\\[39;49;1;27m\[^\r\n\]+\r\n" {
+ -re "^\033\\\[39;49;1;23;24;27m\[^\r\n\]+\r\n" {
exp_continue
}
-re "^$::pagination_prompt$" {
@@ -828,7 +828,7 @@ proc test_pagination_cmd_after_quit_styling {} {
# non-default style that was in use when pagination kicked in
# above.
gdb_test "maintenance time" \
- "^\"\033\\\[39;49;1;27mmaintenance time\033\\\[m\" takes a numeric argument\\."
+ "^\"\033\\\[39;49;1;23;24;27mmaintenance time\033\\\[m\" takes a numeric argument\\."
}
# Helper for test_pagination_prompt_styling. Return false if STR, a
@@ -995,20 +995,20 @@ proc test_pagination_continue_styling_1 { length } {
exp_continue
}
- -re "^The current logfile is \"\033\\\[32;49;22;27m(?:ax)+\033\\\[m" {
+ -re "^The current logfile is \"\033\\\[32;49;22;23;24;27m(?:ax)+\033\\\[m" {
exp_continue
}
- -re "^\r\n\033\\\[32;49;22;27m(?:ax)+\033\\\[m(?=--)" {
+ -re "^\r\n\033\\\[32;49;22;23;24;27m(?:ax)+\033\\\[m(?=--)" {
exp_continue
}
- -re "^\r\n\033\\\[32;49;22;27m(?:ax)+(?=--)" {
+ -re "^\r\n\033\\\[32;49;22;23;24;27m(?:ax)+(?=--)" {
set saw_bad_styling true
exp_continue
}
- -re "^\r\n\033\\\[32;49;22;27m(?:ax)+\033\\\[m\"\\.\r\n" {
+ -re "^\r\n\033\\\[32;49;22;23;24;27m(?:ax)+\033\\\[m\"\\.\r\n" {
exp_continue
}
diff --git a/gdb/testsuite/lib/gdb-utils.exp b/gdb/testsuite/lib/gdb-utils.exp
index fe2cfca..c24e7ed 100644
--- a/gdb/testsuite/lib/gdb-utils.exp
+++ b/gdb/testsuite/lib/gdb-utils.exp
@@ -70,6 +70,8 @@ proc style {str style} {
set fg 39
set bg 49
set intensity 22
+ set italic 23
+ set underline 24
set reverse 27
switch -exact -- $style {
title { set intensity 1 }
@@ -84,7 +86,7 @@ proc style {str style} {
line-number { set intensity 2 }
none { return $str }
}
- return "\033\\\[${fg};${bg};${intensity};${reverse}m${str}\033\\\[m"
+ return "\033\\\[${fg};${bg};${intensity};${italic};${underline};${reverse}m${str}\033\\\[m"
}
# gdb_get_bp_addr num
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 0a582aa..98691df 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5729,6 +5729,10 @@ proc gdb_simple_compile {name code {type object} {compile_flags {}} {object obj}
set ext "d"
break
}
+ if { "$flag" eq "rust" } {
+ set ext "rs"
+ break
+ }
}
set src [standard_temp_file $name.$ext]
set obj [standard_temp_file $name.$postfix]
diff --git a/gdb/top.c b/gdb/top.c
index 72d1953..b097683 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -34,6 +34,7 @@
#include "value.h"
#include "language.h"
#include "terminal.h"
+#include "gdbsupport/cleanups.h"
#include "gdbsupport/job-control.h"
#include "annotate.h"
#include "completer.h"
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 1b4cc82..c97e8fd 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -319,6 +319,8 @@ tui_apply_style (WINDOW *w, ui_file_style style)
wattron (w, A_NORMAL);
wattroff (w, A_BOLD);
wattroff (w, A_DIM);
+ wattroff (w, A_ITALIC);
+ wattroff (w, A_UNDERLINE);
wattroff (w, A_REVERSE);
if (last_color_pair != -1)
wattroff (w, COLOR_PAIR (last_color_pair));
@@ -366,6 +368,12 @@ tui_apply_style (WINDOW *w, ui_file_style style)
gdb_assert_not_reached ("invalid intensity");
}
+ if (style.is_italic ())
+ wattron (w, A_ITALIC);
+
+ if (style.is_underline ())
+ wattron (w, A_UNDERLINE);
+
if (style.is_reverse ())
wattron (w, A_REVERSE);
diff --git a/gdb/ui-style.c b/gdb/ui-style.c
index c8f2e11..9a58e4d 100644
--- a/gdb/ui-style.c
+++ b/gdb/ui-style.c
@@ -290,6 +290,16 @@ ui_file_style::to_ansi () const
else
result.append (std::to_string (m_intensity));
result.push_back (';');
+ if (m_italic)
+ result.append ("3");
+ else
+ result.append ("23");
+ result.push_back (';');
+ if (m_underline)
+ result.append ("4");
+ else
+ result.append ("24");
+ result.push_back (';');
if (m_reverse)
result.push_back ('7');
else
@@ -435,6 +445,14 @@ ui_file_style::parse (const char *buf, size_t *n_read)
/* Dim. */
m_intensity = DIM;
break;
+ case 3:
+ /* Italic. */
+ m_italic = true;
+ break;
+ case 4:
+ /* Underline. */
+ m_underline = true;
+ break;
case 7:
/* Reverse. */
m_reverse = true;
@@ -446,6 +464,14 @@ ui_file_style::parse (const char *buf, size_t *n_read)
/* Normal. */
m_intensity = NORMAL;
break;
+ case 23:
+ /* Non-italic. */
+ m_italic = false;
+ break;
+ case 24:
+ /* Non-underline. */
+ m_underline = false;
+ break;
case 27:
/* Inverse off. */
m_reverse = false;
diff --git a/gdb/ui-style.h b/gdb/ui-style.h
index f61152f..1ea3556 100644
--- a/gdb/ui-style.h
+++ b/gdb/ui-style.h
@@ -266,7 +266,9 @@ struct ui_file_style
return (m_foreground == other.m_foreground
&& m_background == other.m_background
&& m_intensity == other.m_intensity
- && m_reverse == other.m_reverse);
+ && m_reverse == other.m_reverse
+ && m_italic == other.m_italic
+ && m_underline == other.m_underline);
}
bool operator!= (const ui_file_style &other) const
@@ -284,7 +286,9 @@ struct ui_file_style
return (m_foreground == NONE
&& m_background == NONE
&& m_intensity == NORMAL
- && !m_reverse);
+ && !m_reverse
+ && !m_italic
+ && !m_underline);
}
/* Return true if this style specified reverse display; false
@@ -330,6 +334,32 @@ struct ui_file_style
return m_intensity;
}
+ /* Return true if this style specified italic display; false
+ otherwise. */
+ bool is_italic () const
+ {
+ return m_italic;
+ }
+
+ /* Set/clear the italic display flag. */
+ void set_italic (bool italic)
+ {
+ m_italic = italic;
+ }
+
+ /* Return true if this style specified underline display; false
+ otherwise. */
+ bool is_underline () const
+ {
+ return m_underline;
+ }
+
+ /* Set/clear the underline display flag. */
+ void set_underline (bool underline)
+ {
+ m_underline = underline;
+ }
+
/* Parse an ANSI escape sequence in BUF, modifying this style. BUF
must begin with an ESC character. Return true if an escape
sequence was successfully parsed; false otherwise. In either
@@ -351,6 +381,8 @@ private:
color m_foreground = NONE;
color m_background = NONE;
intensity m_intensity = NORMAL;
+ bool m_italic = false;
+ bool m_underline = false;
bool m_reverse = false;
};
diff --git a/gdb/unittests/style-selftests.c b/gdb/unittests/style-selftests.c
index f2a37bb..7cb42a1 100644
--- a/gdb/unittests/style-selftests.c
+++ b/gdb/unittests/style-selftests.c
@@ -38,6 +38,8 @@ run_tests ()
SELF_CHECK (style.get_foreground ().is_none ());
SELF_CHECK (style.get_background ().is_none ());
SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (!style.is_reverse ());
SELF_CHECK (style.to_ansi () == "\033[m");
@@ -47,6 +49,8 @@ run_tests ()
SELF_CHECK (style.get_foreground ().is_none ());
SELF_CHECK (style.get_background ().is_none ());
SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (!style.is_reverse ());
/* This particular case does not round-trip identically, but the
difference is unimportant. */
@@ -57,8 +61,10 @@ run_tests ()
SELF_CHECK (style.get_foreground ().is_none ());
SELF_CHECK (style.get_background ().is_none ());
SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (style.is_reverse ());
- SELF_CHECK (style.to_ansi () == "\033[39;49;22;7m");
+ SELF_CHECK (style.to_ansi () == "\033[39;49;22;23;24;7m");
style = ui_file_style ();
SELF_CHECK (style.parse ("\033[32;1m", &n_read));
@@ -67,8 +73,22 @@ run_tests ()
SELF_CHECK (style.get_foreground ().get_value () == ui_file_style::GREEN);
SELF_CHECK (style.get_background ().is_none ());
SELF_CHECK (style.get_intensity () == ui_file_style::BOLD);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (!style.is_reverse ());
- SELF_CHECK (style.to_ansi () == "\033[32;49;1;27m");
+ SELF_CHECK (style.to_ansi () == "\033[32;49;1;23;24;27m");
+
+ style = ui_file_style ();
+ SELF_CHECK (style.parse ("\033[32;2;3;4m", &n_read));
+ SELF_CHECK (n_read == 11);
+ SELF_CHECK (style.get_foreground ().is_basic ());
+ SELF_CHECK (style.get_foreground ().get_value () == ui_file_style::GREEN);
+ SELF_CHECK (style.get_background ().is_none ());
+ SELF_CHECK (style.get_intensity () == ui_file_style::DIM);
+ SELF_CHECK (style.is_italic ());
+ SELF_CHECK (style.is_underline ());
+ SELF_CHECK (!style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[32;49;2;3;4;27m");
style = ui_file_style ();
SELF_CHECK (style.parse ("\033[38;5;112;48;5;249m", &n_read));
@@ -80,8 +100,10 @@ run_tests ()
style.get_background ().get_rgb (rgb);
CHECK_RGB (0xb2, 0xb2, 0xb2);
SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (!style.is_reverse ());
- SELF_CHECK (style.to_ansi () == "\033[38;5;112;48;5;249;22;27m");
+ SELF_CHECK (style.to_ansi () == "\033[38;5;112;48;5;249;22;23;24;27m");
style = ui_file_style ();
SELF_CHECK (style.parse ("\033[38;2;83;84;85;48;2;0;1;254;2;7m", &n_read));
@@ -93,8 +115,10 @@ run_tests ()
style.get_background ().get_rgb (rgb);
CHECK_RGB (0, 1, 254);
SELF_CHECK (style.get_intensity () == ui_file_style::DIM);
+ SELF_CHECK (!style.is_italic ());
+ SELF_CHECK (!style.is_underline ());
SELF_CHECK (style.is_reverse ());
- SELF_CHECK (style.to_ansi () == "\033[38;2;83;84;85;48;2;0;1;254;2;7m");
+ SELF_CHECK (style.to_ansi () == "\033[38;2;83;84;85;48;2;0;1;254;2;23;24;7m");
}
} /* namespace style */
diff --git a/gdb/value.c b/gdb/value.c
index 5574642..82d9a86 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -45,6 +45,7 @@
#include <utility>
#include <vector>
#include "completer.h"
+#include "gdbsupport/cleanups.h"
#include "gdbsupport/selftest.h"
#include "gdbsupport/array-view.h"
#include "cli/cli-style.h"
diff --git a/gdbsupport/common-defs.h b/gdbsupport/common-defs.h
index cfdefe1..8d7e2a9 100644
--- a/gdbsupport/common-defs.h
+++ b/gdbsupport/common-defs.h
@@ -216,7 +216,6 @@
#include "errors.h"
#include "print-utils.h"
#include "common-debug.h"
-#include "cleanups.h"
#include "common-exceptions.h"
#include "gdbsupport/poison.h"
diff --git a/ld/testsuite/ld-plugin/lto-binutils.exp b/ld/testsuite/ld-plugin/lto-binutils.exp
index 88d3517..de017f0 100644
--- a/ld/testsuite/ld-plugin/lto-binutils.exp
+++ b/ld/testsuite/ld-plugin/lto-binutils.exp
@@ -355,3 +355,178 @@ run_cc_link_tests [list \
"tmpdir/libstrip-1b-fat-s.a" \
] \
]
+
+proc run_pr33246_test { llvm fat } {
+ global srcdir
+ global subdir
+ global plug_opt
+ global llvm_plug_opt
+ global ar
+ global CLANG_FOR_TARGET
+ global CC_FOR_TARGET
+ global NM
+ global READELF
+ global strip
+
+ set strip_flags "--strip-debug --enable-deterministic-archives"
+
+ set test pr33246
+ set testname "${test}${llvm}${fat} with $strip_flags"
+
+ if { "$llvm" == "-llvm" } {
+ # Skip native x32 and i?86 targets since system LLVMgold.so may
+ # not be compatible with native x32 and i?86 targets binutils.
+ if { [istarget "x86_64-*-linux*-gnux32"]
+ || [istarget "i?86-*-*"]
+ || ![info exists CLANG_FOR_TARGET]
+ || [string match "" $llvm_plug_opt] } then {
+ untested $testname
+ return
+ }
+ set CC $CLANG_FOR_TARGET
+ set binutils_plug_opt "$llvm_plug_opt"
+ } else {
+ if { ![info exists CC_FOR_TARGET]
+ || [string match "" $plug_opt] } then {
+ untested $testname
+ return
+ }
+ set CC $CC_FOR_TARGET
+ set binutils_plug_opt "$plug_opt"
+ }
+
+ append strip_flags " $binutils_plug_opt"
+
+ set src $srcdir/$subdir/${test}.c
+ set obj tmpdir/${test}${llvm}${fat}.o
+ set archive tmpdir/${test}${llvm}${fat}.a
+ set CFLAGS "-c -g -O2 -flto"
+ if { "$fat" == "-fat" } {
+ append CFLAGS " -ffat-lto-objects"
+ } else {
+ append CFLAGS " -fno-fat-lto-objects"
+ }
+
+ set cmd "$CC $CFLAGS -o $obj $src"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname ($obj)"
+ return
+ }
+
+ set cmd "$strip $strip_flags $obj -o ${obj}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $obj)"
+ return
+ }
+
+ set cmd "$NM $binutils_plug_opt ${obj}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![regexp "0+ T foo" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $obj)"
+ return
+ }
+
+ if { "$fat" == "-fat" } {
+ set cmd "$READELF -SW ${obj}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if [regexp " \.debug_" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $obj)"
+ return
+ }
+ } else {
+ set cmd "cmp $obj ${obj}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $obj)"
+ return
+ }
+ }
+
+ pass "$testname (strip $obj)"
+
+ set cmd "$ar $binutils_plug_opt -D -s -r -c $archive $obj"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname ($archive)"
+ return
+ }
+
+ set cmd "$strip $strip_flags $archive -o ${archive}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $archive)"
+ return
+ }
+
+ set cmd "$NM $binutils_plug_opt ${archive}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![regexp "0+ T foo" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $archive)"
+ return
+ }
+
+ if { "$fat" == "-fat" } {
+ set cmd "$READELF -SW ${archive}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if [regexp " \.debug_" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $archive)"
+ return
+ }
+ } else {
+ set cmd "cmp $archive ${archive}.strip"
+ send_log "$cmd\n"
+ verbose "$cmd" 1
+ catch "exec $cmd" got
+ if ![string match "" $got] then {
+ send_log "$got\n"
+ verbose "$got" 1
+ fail "$testname (strip $archive)"
+ return
+ }
+ }
+
+ pass "$testname (strip $archive)"
+}
+
+run_pr33246_test "" ""
+run_pr33246_test "" "-fat"
+run_pr33246_test "-llvm" ""
+run_pr33246_test "-llvm" "-fat"
diff --git a/ld/testsuite/ld-plugin/pr33246.c b/ld/testsuite/ld-plugin/pr33246.c
new file mode 100644
index 0000000..cd0130c
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr33246.c
@@ -0,0 +1,4 @@
+void
+foo (void)
+{
+}