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