db51e6
diff -rup binutils.orig/bfd/Makefile.am binutils-2.30/bfd/Makefile.am
db51e6
--- binutils.orig/bfd/Makefile.am	2022-08-19 12:00:54.247630878 +0100
db51e6
+++ binutils-2.30/bfd/Makefile.am	2022-08-19 12:20:51.714655518 +0100
db51e6
@@ -52,7 +52,7 @@ ZLIBINC = @zlibinc@
db51e6
 WARN_CFLAGS = @WARN_CFLAGS@
db51e6
 NO_WERROR = @NO_WERROR@
db51e6
 AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
db51e6
-AM_CPPFLAGS = -DBINDIR='"$(bindir)"'
db51e6
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"' 
db51e6
 if PLUGINS
db51e6
 bfdinclude_HEADERS += $(INCDIR)/plugin-api.h
db51e6
 LIBDL = @lt_cv_dlopen_libs@
db51e6
diff -rup binutils.orig/bfd/Makefile.in binutils-2.30/bfd/Makefile.in
db51e6
--- binutils.orig/bfd/Makefile.in	2022-08-19 12:00:54.248630872 +0100
db51e6
+++ binutils-2.30/bfd/Makefile.in	2022-08-19 12:21:24.788462670 +0100
db51e6
@@ -390,7 +390,7 @@ libbfd_la_LDFLAGS = -Wl,-Bsymbolic-funct
db51e6
 ZLIB = @zlibdir@ -lz
db51e6
 ZLIBINC = @zlibinc@
db51e6
 AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC)
db51e6
-AM_CPPFLAGS = -DBINDIR='"$(bindir)"'
db51e6
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DLIBDIR='"$(libdir)"'
db51e6
 @PLUGINS_TRUE@LIBDL = @lt_cv_dlopen_libs@
db51e6
 
db51e6
 # bfd.h goes here, for now
db51e6
diff -rup binutils.orig/bfd/plugin.c binutils-2.30/bfd/plugin.c
db51e6
--- binutils.orig/bfd/plugin.c	2022-08-19 12:00:54.248630872 +0100
db51e6
+++ binutils-2.30/bfd/plugin.c	2022-08-19 12:24:10.466496616 +0100
db51e6
@@ -348,16 +348,44 @@ try_claim (bfd *abfd)
db51e6
   return claimed;
db51e6
 }
db51e6
 
db51e6
+struct plugin_list_entry
db51e6
+{
db51e6
+  /* These must be initialized for each IR object with LTO wrapper.  */
db51e6
+  ld_plugin_claim_file_handler claim_file;
db51e6
+  ld_plugin_all_symbols_read_handler all_symbols_read;
db51e6
+  ld_plugin_all_symbols_read_handler cleanup_handler;
db51e6
+  bfd_boolean has_symbol_type;
db51e6
+
db51e6
+  struct plugin_list_entry *next;
db51e6
+
db51e6
+  /* These can be reused for all IR objects.  */
db51e6
+  const char *plugin_name;
db51e6
+};
db51e6
+
db51e6
+static struct plugin_list_entry *plugin_list = NULL;
db51e6
+static struct plugin_list_entry *current_plugin = NULL;
db51e6
+
db51e6
 static int
db51e6
-try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p, bfd_boolean build_list_p)
db51e6
+try_load_plugin (const char *pname,
db51e6
+		 struct plugin_list_entry *plugin_list_iter,
db51e6
+		 bfd *abfd,
db51e6
+		 bfd_boolean build_list_p)
db51e6
 {
db51e6
   void *plugin_handle;
db51e6
   struct ld_plugin_tv tv[4];
db51e6
   int i;
db51e6
   ld_plugin_onload onload;
db51e6
   enum ld_plugin_status status;
db51e6
+  int result = 0;
db51e6
+
db51e6
+  /* NB: Each object is independent.  Reuse the previous plugin from
db51e6
+     the last run will lead to wrong result.  */
db51e6
+  if (current_plugin)
db51e6
+    memset (current_plugin, 0,
db51e6
+	    offsetof (struct plugin_list_entry, next));
db51e6
 
db51e6
-  *has_plugin_p = 0;
db51e6
+  if (plugin_list_iter)
db51e6
+    pname = plugin_list_iter->plugin_name;
db51e6
 
db51e6
   plugin_handle = dlopen (pname, RTLD_NOW);
db51e6
   if (!plugin_handle)
db51e6
@@ -366,13 +394,40 @@ try_load_plugin (const char *pname, bfd
db51e6
 	 we do not bother the user with the details of any
db51e6
 	 plugins that cannot be loaded.  */
db51e6
       if (! build_list_p)
db51e6
-	_bfd_error_handler ("%s\n", dlerror ());
db51e6
+	_bfd_error_handler ("Failed to load plugin '%s', reason: %s\n",
db51e6
+			    pname, dlerror ());
db51e6
       return 0;
db51e6
     }
db51e6
 
db51e6
+  if (plugin_list_iter == NULL)
db51e6
+    {
db51e6
+      size_t length_plugin_name = strlen (pname) + 1;
db51e6
+      char *plugin_name = bfd_malloc (length_plugin_name);
db51e6
+
db51e6
+      if (plugin_name == NULL)
db51e6
+	goto short_circuit;
db51e6
+      plugin_list_iter = bfd_malloc (sizeof *plugin_list_iter);
db51e6
+      if (plugin_list_iter == NULL)
db51e6
+	{
db51e6
+	  free (plugin_name);
db51e6
+	  goto short_circuit;
db51e6
+	}
db51e6
+      /* Make a copy of PNAME since PNAME from load_plugin () will be
db51e6
+	 freed.  */
db51e6
+      memcpy (plugin_name, pname, length_plugin_name);
db51e6
+      memset (plugin_list_iter, 0, sizeof (*plugin_list_iter));
db51e6
+      plugin_list_iter->plugin_name = plugin_name;
db51e6
+      plugin_list_iter->next = plugin_list;
db51e6
+      plugin_list = plugin_list_iter;
db51e6
+    }
db51e6
+
db51e6
+  current_plugin = plugin_list_iter;
db51e6
+  if (build_list_p)
db51e6
+    goto short_circuit;
db51e6
+
db51e6
   onload = dlsym (plugin_handle, "onload");
db51e6
   if (!onload)
db51e6
-    goto err;
db51e6
+    goto short_circuit;
db51e6
 
db51e6
   i = 0;
db51e6
   tv[i].tv_tag = LDPT_MESSAGE;
db51e6
@@ -393,34 +448,26 @@ try_load_plugin (const char *pname, bfd
db51e6
   status = (*onload)(tv);
db51e6
 
db51e6
   if (status != LDPS_OK)
db51e6
-    goto err;
db51e6
-
db51e6
-  *has_plugin_p = 1;
db51e6
+    goto short_circuit;
db51e6
 
db51e6
   abfd->plugin_format = bfd_plugin_no;
db51e6
 
db51e6
-  if (!claim_file)
db51e6
-    goto err;
db51e6
+  if (!current_plugin->claim_file)
db51e6
+    goto short_circuit;
db51e6
 
db51e6
   if (!try_claim (abfd))
db51e6
-    goto err;
db51e6
+    goto short_circuit;
db51e6
 
db51e6
   abfd->plugin_format = bfd_plugin_yes;
db51e6
+  result = 1;
db51e6
 
db51e6
-  /* There is a potential resource leak here, but it is not important.  */
db51e6
-  /* coverity[leaked_storage: FALSE] */
db51e6
-  return 1;
db51e6
-
db51e6
- err:
db51e6
-  /* There is a potential resource leak here, but it is not important.  */
db51e6
-  /* coverity[leaked_storage: FALSE] */
db51e6
-  return 0;
db51e6
+ short_circuit:
db51e6
+  dlclose (plugin_handle);
db51e6
+  return result;
db51e6
 }
db51e6
 
db51e6
 /* There may be plugin libraries in lib/bfd-plugins.  */
db51e6
 
db51e6
-static int has_plugin = -1;
db51e6
-
db51e6
 static const bfd_target *(*ld_plugin_object_p) (bfd *);
db51e6
 
db51e6
 static const char *plugin_name;
db51e6
@@ -429,7 +476,6 @@ void
db51e6
 bfd_plugin_set_plugin (const char *p)
db51e6
 {
db51e6
   plugin_name = p;
db51e6
-  has_plugin = p != NULL;
db51e6
 }
db51e6
 
db51e6
 /* Return TRUE if a plugin library is used.  */
db51e6
@@ -437,7 +483,7 @@ bfd_plugin_set_plugin (const char *p)
db51e6
 bfd_boolean
db51e6
 bfd_plugin_specified_p (void)
db51e6
 {
db51e6
-  return has_plugin > 0;
db51e6
+  return plugin_list != NULL;
db51e6
 }
db51e6
 
db51e6
 /* Return TRUE if ABFD can be claimed by linker LTO plugin.  */
db51e6
@@ -468,60 +514,92 @@ register_ld_plugin_object_p (const bfd_t
db51e6
   ld_plugin_object_p = object_p;
db51e6
 }
db51e6
 
db51e6
+/* There may be plugin libraries in lib/bfd-plugins.  */
db51e6
+static int has_plugin_list = -1;
db51e6
+
db51e6
+static void
db51e6
+build_plugin_list (bfd *abfd)
db51e6
+{
db51e6
+  /* The intent was to search ${libdir}/bfd-plugins for plugins, but
db51e6
+     unfortunately the original implementation wasn't precisely that
db51e6
+     when configuring binutils using --libdir.  Search in the proper
db51e6
+     path first, then the old one for backwards compatibility.  */
db51e6
+  static const char *path[]
db51e6
+    = { LIBDIR "/bfd-plugins",
db51e6
+	BINDIR "/../lib/bfd-plugins" };
db51e6
+  struct stat last_st;
db51e6
+  unsigned int i;
db51e6
+
db51e6
+  if (has_plugin_list >= 0)
db51e6
+    return;
db51e6
+
db51e6
+  /* Try not to search the same dir twice, by looking at st_dev and
db51e6
+     st_ino for the dir.  If we are on a file system that always sets
db51e6
+     st_ino to zero or the actual st_ino is zero we might waste some
db51e6
+     time, but that doesn't matter too much.  */
db51e6
+  last_st.st_dev = 0;
db51e6
+  last_st.st_ino = 0;
db51e6
+  for (i = 0; i < sizeof (path) / sizeof (path[0]); i++)
db51e6
+    {
db51e6
+      char *plugin_dir = make_relative_prefix (plugin_program_name,
db51e6
+					       BINDIR,
db51e6
+					       path[i]);
db51e6
+      if (plugin_dir)
db51e6
+	{
db51e6
+	  struct stat st;
db51e6
+	  DIR *d;
db51e6
+
db51e6
+	  if (stat (plugin_dir, &st) == 0
db51e6
+	      && S_ISDIR (st.st_mode)
db51e6
+	      && !(last_st.st_dev == st.st_dev
db51e6
+		   && last_st.st_ino == st.st_ino
db51e6
+		   && st.st_ino != 0)
db51e6
+	      && (d = opendir (plugin_dir)) != NULL)
db51e6
+	    {
db51e6
+	      struct dirent *ent;
db51e6
+
db51e6
+	      last_st.st_dev = st.st_dev;
db51e6
+	      last_st.st_ino = st.st_ino;
db51e6
+	      while ((ent = readdir (d)) != NULL)
db51e6
+		{
db51e6
+		  char *full_name;
db51e6
+
db51e6
+		  full_name = concat (plugin_dir, "/", ent->d_name, NULL);
db51e6
+		  if (stat (full_name, &st) == 0 && S_ISREG (st.st_mode))
db51e6
+		    (void) try_load_plugin (full_name, NULL, abfd, TRUE);
db51e6
+		  free (full_name);
db51e6
+		}
db51e6
+	      closedir (d);
db51e6
+	    }
db51e6
+	  free (plugin_dir);
db51e6
+	}
db51e6
+    }
db51e6
+
db51e6
+  has_plugin_list = plugin_list != NULL;
db51e6
+}
db51e6
+
db51e6
 static int
db51e6
 load_plugin (bfd *abfd)
db51e6
 {
db51e6
-  char *plugin_dir;
db51e6
-  char *p;
db51e6
-  DIR *d;
db51e6
-  struct dirent *ent;
db51e6
-  int found = 0;
db51e6
+  struct plugin_list_entry *plugin_list_iter;
db51e6
 
db51e6
-  if (!has_plugin)
db51e6
-    return found;
db51e6
-
db51e6
-  if (plugin_name)
db51e6
-    return try_load_plugin (plugin_name, abfd, &has_plugin, FALSE);
db51e6
+  if (plugin_name != NULL)
db51e6
+    return try_load_plugin (plugin_name, plugin_list, abfd, FALSE);
db51e6
 
db51e6
   if (plugin_program_name == NULL)
db51e6
-    return found;
db51e6
-
db51e6
-  plugin_dir = concat (BINDIR, "/../lib/bfd-plugins", NULL);
db51e6
-  p = make_relative_prefix (plugin_program_name,
db51e6
-			    BINDIR,
db51e6
-			    plugin_dir);
db51e6
-  free (plugin_dir);
db51e6
-  plugin_dir = NULL;
db51e6
-
db51e6
-  d = opendir (p);
db51e6
-  if (!d)
db51e6
-    goto out;
db51e6
+    return 0;
db51e6
 
db51e6
-  while ((ent = readdir (d)))
db51e6
-    {
db51e6
-      char *full_name;
db51e6
-      struct stat s;
db51e6
-      int valid_plugin;
db51e6
-
db51e6
-      full_name = concat (p, "/", ent->d_name, NULL);
db51e6
-      if (stat(full_name, &s) == 0 && S_ISREG (s.st_mode))
db51e6
-	found = try_load_plugin (full_name, abfd, &valid_plugin, TRUE);
db51e6
-      if (has_plugin <= 0)
db51e6
-	has_plugin = valid_plugin;
db51e6
-      free (full_name);
db51e6
-      if (found)
db51e6
-	break;
db51e6
-    }
db51e6
+  build_plugin_list (abfd);
db51e6
 
db51e6
- out:
db51e6
-  free (p);
db51e6
-  if (d)
db51e6
-    closedir (d);
db51e6
+  for (plugin_list_iter = plugin_list;
db51e6
+       plugin_list_iter;
db51e6
+       plugin_list_iter = plugin_list_iter->next)
db51e6
+    if (try_load_plugin (NULL, plugin_list_iter, abfd, FALSE))
db51e6
+      return 1;
db51e6
 
db51e6
-  return found;
db51e6
+  return 0;
db51e6
 }
db51e6
 
db51e6
-
db51e6
 static const bfd_target *
db51e6
 bfd_plugin_object_p (bfd *abfd)
db51e6
 {
db51e6
--- binutils.orig/bfd/plugin.c	2022-08-19 13:54:29.289173969 +0100
db51e6
+++ binutils-2.30/bfd/plugin.c	2022-08-19 14:13:24.077310901 +0100
db51e6
@@ -122,13 +122,29 @@ message (int level ATTRIBUTE_UNUSED,
db51e6
   return LDPS_OK;
db51e6
 }
db51e6
 
db51e6
+struct plugin_list_entry
db51e6
+{
db51e6
+  /* These must be initialized for each IR object with LTO wrapper.  */
db51e6
+  ld_plugin_claim_file_handler claim_file;
db51e6
+  ld_plugin_all_symbols_read_handler all_symbols_read;
db51e6
+  ld_plugin_all_symbols_read_handler cleanup_handler;
db51e6
+  bfd_boolean has_symbol_type;
db51e6
+
db51e6
+  struct plugin_list_entry *next;
db51e6
+
db51e6
+  /* These can be reused for all IR objects.  */
db51e6
+  const char *plugin_name;
db51e6
+};
db51e6
+
db51e6
+static struct plugin_list_entry *plugin_list = NULL;
db51e6
+static struct plugin_list_entry *current_plugin = NULL;
db51e6
+
db51e6
 /* Register a claim-file handler. */
db51e6
-static ld_plugin_claim_file_handler claim_file;
db51e6
 
db51e6
 static enum ld_plugin_status
db51e6
 register_claim_file (ld_plugin_claim_file_handler handler)
db51e6
 {
db51e6
-  claim_file = handler;
db51e6
+  current_plugin->claim_file = handler;
db51e6
   return LDPS_OK;
db51e6
 }
db51e6
 
db51e6
@@ -339,32 +355,17 @@ try_claim (bfd *abfd)
db51e6
   int claimed = 0;
db51e6
   struct ld_plugin_input_file file;
db51e6
 
db51e6
+  if (current_plugin->claim_file == NULL)
db51e6
+    return 0;
db51e6
   if (!bfd_plugin_open_input (abfd, &file))
db51e6
     return 0;
db51e6
   file.handle = abfd;
db51e6
   off_t cur_offset = lseek (file.fd, 0, SEEK_CUR);
db51e6
-  claim_file (&file, &claimed);
db51e6
+  current_plugin->claim_file (&file, &claimed);
db51e6
   lseek (file.fd, cur_offset, SEEK_SET);
db51e6
   return claimed;
db51e6
 }
db51e6
 
db51e6
-struct plugin_list_entry
db51e6
-{
db51e6
-  /* These must be initialized for each IR object with LTO wrapper.  */
db51e6
-  ld_plugin_claim_file_handler claim_file;
db51e6
-  ld_plugin_all_symbols_read_handler all_symbols_read;
db51e6
-  ld_plugin_all_symbols_read_handler cleanup_handler;
db51e6
-  bfd_boolean has_symbol_type;
db51e6
-
db51e6
-  struct plugin_list_entry *next;
db51e6
-
db51e6
-  /* These can be reused for all IR objects.  */
db51e6
-  const char *plugin_name;
db51e6
-};
db51e6
-
db51e6
-static struct plugin_list_entry *plugin_list = NULL;
db51e6
-static struct plugin_list_entry *current_plugin = NULL;
db51e6
-
db51e6
 static int
db51e6
 try_load_plugin (const char *pname,
db51e6
 		 struct plugin_list_entry *plugin_list_iter,