Automatic date update in version.in
[binutils-gdb.git] / bfd / plugin.c
index bed98520da0732301e067918c213eb768e468469..fb45cbee514ead62517628552e29d31fde7ec7f5 100644 (file)
@@ -1,5 +1,5 @@
 /* Plugin support for BFD.
-   Copyright (C) 2009-2020 Free Software Foundation, Inc.
+   Copyright (C) 2009-2022 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -130,7 +130,7 @@ struct plugin_list_entry
   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;
+  bool has_symbol_type;
 
   struct plugin_list_entry *next;
 
@@ -184,7 +184,7 @@ static enum ld_plugin_status
 add_symbols_v2 (void *handle, int nsyms,
                const struct ld_plugin_symbol *syms)
 {
-  current_plugin->has_symbol_type = TRUE;
+  current_plugin->has_symbol_type = true;
   return add_symbols (handle, nsyms, syms);
 }
 
@@ -192,6 +192,7 @@ int
 bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
 {
   bfd *iobfd;
+  int fd;
 
   iobfd = ibfd;
   while (iobfd->my_archive
@@ -202,22 +203,60 @@ bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
   if (!iobfd->iostream && !bfd_open_file (iobfd))
     return 0;
 
-  /* The plugin API expects that the file descriptor won't be closed
-     and reused as done by the bfd file cache.  So open it again.
-     dup isn't good enough.  plugin IO uses lseek/read while BFD uses
-     fseek/fread.  It isn't wise to mix the unistd and stdio calls on
-     the same underlying file descriptor.  */
-  file->fd = open (file->name, O_RDONLY | O_BINARY);
-  if (file->fd < 0)
-    return 0;
+  /* Reuse the archive plugin file descriptor.  */
+  if (iobfd != ibfd)
+    fd = iobfd->archive_plugin_fd;
+  else
+    fd = -1;
+
+  if (fd < 0)
+    {
+      /* The plugin API expects that the file descriptor won't be closed
+        and reused as done by the bfd file cache.  So open it again.
+        dup isn't good enough.  plugin IO uses lseek/read while BFD uses
+        fseek/fread.  It isn't wise to mix the unistd and stdio calls on
+        the same underlying file descriptor.  */
+      fd = open (file->name, O_RDONLY | O_BINARY);
+      if (fd < 0)
+       {
+#ifndef EMFILE
+         return 0;
+#else
+         if (errno != EMFILE)
+           return 0;
+
+#ifdef HAVE_GETRLIMIT
+         struct rlimit lim;
+
+         /* Complicated links involving lots of files and/or large
+            archives can exhaust the number of file descriptors
+            available to us.  If possible, try to allocate more
+            descriptors.  */
+         if (getrlimit (RLIMIT_NOFILE, & lim) == 0
+             && lim.rlim_cur < lim.rlim_max)
+           {
+             lim.rlim_cur = lim.rlim_max;
+             if (setrlimit (RLIMIT_NOFILE, &lim) == 0)
+               fd = open (file->name, O_RDONLY | O_BINARY);
+           }
+
+         if (fd < 0)
+#endif
+           {
+             _bfd_error_handler (_("plugin framework: out of file descriptors. Try using fewer objects/archives\n"));
+             return 0;
+           }
+#endif
+       }
+    }
 
   if (iobfd == ibfd)
     {
       struct stat stat_buf;
 
-      if (fstat (file->fd, &stat_buf))
+      if (fstat (fd, &stat_buf))
        {
-         close(file->fd);
+         close (fd);
          return 0;
        }
 
@@ -226,12 +265,51 @@ bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
     }
   else
     {
+      /* Cache the archive plugin file descriptor.  */
+      iobfd->archive_plugin_fd = fd;
+      iobfd->archive_plugin_fd_open_count++;
+
       file->offset = ibfd->origin;
       file->filesize = arelt_size (ibfd);
     }
+
+  file->fd = fd;
   return 1;
 }
 
+/* Close the plugin file descriptor FD.  If ABFD isn't NULL, it is an
+   archive member.   */
+
+void
+bfd_plugin_close_file_descriptor (bfd *abfd, int fd)
+{
+  if (abfd == NULL)
+    close (fd);
+  else
+    {
+      while (abfd->my_archive
+            && !bfd_is_thin_archive (abfd->my_archive))
+       abfd = abfd->my_archive;
+
+      /* Close the file descriptor if there is no archive plugin file
+        descriptor.  */
+      if (abfd->archive_plugin_fd == -1)
+       {
+         close (fd);
+         return;
+       }
+
+      abfd->archive_plugin_fd_open_count--;
+      /* Dup the archive plugin file descriptor for later use, which
+        will be closed by _bfd_archive_close_and_cleanup.  */
+      if (abfd->archive_plugin_fd_open_count == 0)
+       {
+         abfd->archive_plugin_fd = dup (fd);
+         close (fd);
+       }
+    }
+}
+
 static int
 try_claim (bfd *abfd)
 {
@@ -243,24 +321,26 @@ try_claim (bfd *abfd)
       && current_plugin->claim_file)
     {
       current_plugin->claim_file (&file, &claimed);
-      close (file.fd);
+      bfd_plugin_close_file_descriptor ((abfd->my_archive != NULL
+                                        ? abfd : NULL),
+                                       file.fd);
     }
 
   return claimed;
 }
 
-static bfd_boolean
-try_load_plugin (const char *                pname,
-                struct plugin_list_entry *  plugin_list_iter,
-                bfd *                       abfd,
-                bfd_boolean                 build_list_p)
+static bool
+try_load_plugin (const char *pname,
+                struct plugin_list_entry *plugin_list_iter,
+                bfd *abfd,
+                bool build_list_p)
 {
   void *plugin_handle;
   struct ld_plugin_tv tv[5];
   int i;
   ld_plugin_onload onload;
   enum ld_plugin_status status;
-  bfd_boolean result = FALSE;
+  bool result = false;
 
   /* NB: Each object is independent.  Reuse the previous plugin from
      the last run will lead to wrong result.  */
@@ -280,7 +360,7 @@ try_load_plugin (const char *                pname,
       if (! build_list_p)
        _bfd_error_handler ("Failed to load plugin '%s', reason: %s\n",
                            pname, dlerror ());
-      return FALSE;
+      return false;
     }
 
   if (plugin_list_iter == NULL)
@@ -348,7 +428,7 @@ try_load_plugin (const char *                pname,
     goto short_circuit;
 
   abfd->plugin_format = bfd_plugin_yes;
-  result = TRUE;
+  result = true;
 
  short_circuit:
   dlclose (plugin_handle);
@@ -370,7 +450,7 @@ bfd_plugin_set_plugin (const char *p)
 
 /* Return TRUE if a plugin library is used.  */
 
-bfd_boolean
+bool
 bfd_plugin_specified_p (void)
 {
   return plugin_list != NULL;
@@ -378,19 +458,19 @@ bfd_plugin_specified_p (void)
 
 /* Return TRUE if ABFD can be claimed by linker LTO plugin.  */
 
-bfd_boolean
+bool
 bfd_link_plugin_object_p (bfd *abfd)
 {
   if (ld_plugin_object_p)
     return ld_plugin_object_p (abfd) != NULL;
-  return FALSE;
+  return false;
 }
 
 extern const bfd_target plugin_vec;
 
 /* Return TRUE if TARGET is a pointer to plugin_vec.  */
 
-bfd_boolean
+bool
 bfd_plugin_target_p (const bfd_target *target)
 {
   return target == &plugin_vec;
@@ -452,7 +532,7 @@ build_plugin_list (bfd *abfd)
 
                  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);
+                   (void) try_load_plugin (full_name, NULL, abfd, true);
                  free (full_name);
                }
              closedir (d);
@@ -464,26 +544,26 @@ build_plugin_list (bfd *abfd)
   has_plugin_list = plugin_list != NULL;
 }
 
-static bfd_boolean
+static bool
 load_plugin (bfd *abfd)
 {
   struct plugin_list_entry *plugin_list_iter;
 
   if (plugin_name)
-    return try_load_plugin (plugin_name, plugin_list, abfd, FALSE);
+    return try_load_plugin (plugin_name, plugin_list, abfd, false);
 
   if (plugin_program_name == NULL)
-    return FALSE;
+    return false;
 
   build_plugin_list (abfd);
 
   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 TRUE;
+    if (try_load_plugin (NULL, plugin_list_iter, abfd, false))
+      return true;
 
-  return FALSE;
+  return false;
 }
 
 
@@ -502,45 +582,45 @@ bfd_plugin_object_p (bfd *abfd)
 /* Copy any private info we understand from the input bfd
    to the output bfd.  */
 
-static bfd_boolean
+static bool
 bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
                                      bfd *obfd ATTRIBUTE_UNUSED)
 {
   BFD_ASSERT (0);
-  return TRUE;
+  return true;
 }
 
 /* Copy any private info we understand from the input section
    to the output section.  */
 
-static bfd_boolean
+static bool
 bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
                                          asection *isection ATTRIBUTE_UNUSED,
                                          bfd *obfd ATTRIBUTE_UNUSED,
                                          asection *osection ATTRIBUTE_UNUSED)
 {
   BFD_ASSERT (0);
-  return TRUE;
+  return true;
 }
 
 /* Copy any private info we understand from the input symbol
    to the output symbol.  */
 
-static bfd_boolean
+static bool
 bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
                                         asymbol *isymbol ATTRIBUTE_UNUSED,
                                         bfd *obfd ATTRIBUTE_UNUSED,
                                         asymbol *osymbol ATTRIBUTE_UNUSED)
 {
   BFD_ASSERT (0);
-  return TRUE;
+  return true;
 }
 
-static bfd_boolean
+static bool
 bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, PTR ptr ATTRIBUTE_UNUSED)
 {
   BFD_ASSERT (0);
-  return TRUE;
+  return true;
 }
 
 static char *
@@ -719,6 +799,7 @@ const bfd_target plugin_vec =
   '/',                         /* ar_pad_char.  */
   15,                          /* ar_max_namelen.  */
   255,                         /* match priority.  */
+  TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
 
   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
   bfd_getl32, bfd_getl_signed_32, bfd_putl32,