+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;
+ char *resolution_file;
+ char *resolution_option;
+ bfd *real_bfd;
+ long real_nsyms;
+ asymbol **real_syms;
+ int lto_nsyms;
+ const struct ld_plugin_symbol *lto_syms;
+
+ struct plugin_list_entry *next;
+
+ /* These can be reused for all IR objects. */
+ const char *plugin_name;
+ char *gcc;
+ char *lto_wrapper;
+ char *gcc_env;
+ bfd_boolean initialized;
+};
+
+static const char *plugin_program_name;
+static int need_lto_wrapper_p;
+
+void
+bfd_plugin_set_program_name (const char *program_name,
+ int need_lto_wrapper)
+{
+ plugin_program_name = program_name;
+ need_lto_wrapper_p = need_lto_wrapper;
+}
+
+/* Use GCC LTO wrapper to covert LTO IR object to the real object. */
+
+static bfd_boolean
+get_lto_wrapper (struct plugin_list_entry *plugin)
+{
+ struct stat st;
+ const char *real_name;
+ const char *base_name;
+ size_t length;
+ const char *target_start = NULL;
+ const char *target_end = NULL;
+ size_t target_length = 0;
+ char *gcc_name;
+ char *wrapper_name;
+ char *p;
+ char dir_seperator = '\0';
+ char *resolution_file;
+
+ if (!need_lto_wrapper_p)
+ return FALSE;
+
+ if (plugin->initialized)
+ {
+ if (plugin->lto_wrapper)
+ {
+ resolution_file = make_temp_file (".res");
+ if (resolution_file)
+ {
+ plugin->resolution_file = resolution_file;
+ plugin->resolution_option = concat ("-fresolution=",
+ resolution_file, NULL);
+ return TRUE;
+ }
+ else
+ {
+ /* Something is wrong. Give up. */
+ free (plugin->gcc);
+ free (plugin->lto_wrapper);
+ free (plugin->gcc_env);
+ plugin->gcc = NULL;
+ plugin->gcc_env = NULL;
+ plugin->lto_wrapper = NULL;
+ }
+ }
+
+ return FALSE;
+ }
+
+ plugin->initialized = TRUE;
+
+ /* Check for PREFIX/libexec/gcc/TARGET/VERSION/liblto_plugin.so. */
+ real_name = lrealpath (plugin->plugin_name);
+ base_name = lbasename (real_name);
+
+ /* The directory length in plugin pathname. */
+ length = base_name - real_name;
+
+ /* Skip if there is no PREFIX. */
+ if (!length)
+ return FALSE;
+
+ p = (char *) real_name + length - 1;
+ if (IS_DIR_SEPARATOR (*p))
+ {
+ int level = 0;
+ for (; p != real_name; p--)
+ if (IS_DIR_SEPARATOR (*p))
+ {
+ level++;
+ if (level == 2)
+ target_end = p;
+ else if (level == 3)
+ {
+ target_start = p + 1;
+ target_length = target_end - target_start;
+ }
+ else if (level == 5)
+ {
+ dir_seperator = *p;
+ break;
+ }
+ }
+ }
+
+ /* Skip if there is no TARGET nor PREFIX. */
+ if (!target_length || !dir_seperator)
+ return FALSE;
+
+#ifdef HAVE_EXECUTABLE_SUFFIX
+# define GCC_EXECUTABLE "gcc" EXECUTABLE_SUFFIX
+# define LTO_WRAPPER_EXECUTABLE "lto-wrapper" EXECUTABLE_SUFFIX
+#else
+# define GCC_EXECUTABLE "gcc"
+# define LTO_WRAPPER_EXECUTABLE "lto-wrapper"
+#endif
+ gcc_name = bfd_malloc (length + target_length
+ + sizeof (GCC_EXECUTABLE));
+ if (gcc_name == NULL)
+ return FALSE;
+ memcpy (gcc_name, real_name, length);
+
+ /* Get PREFIX/bin/. */
+ p += gcc_name - real_name;
+ memcpy (p + 1, "bin", 3);
+ p[4] = dir_seperator;
+
+ /* Try PREFIX/bin/TARGET-gcc first. */
+ memcpy (p + 5, target_start, target_length);
+ p[5 + target_length] = '-';
+ memcpy (p + 5 + target_length + 1, GCC_EXECUTABLE,
+ sizeof (GCC_EXECUTABLE));
+ if (stat (gcc_name, &st) != 0 || !S_ISREG (st.st_mode))
+ {
+ /* Then try PREFIX/bin/gcc. */
+ memcpy (p + 5, GCC_EXECUTABLE, sizeof (GCC_EXECUTABLE));
+ if (stat (gcc_name, &st) != 0 || !S_ISREG (st.st_mode))
+ {
+ free (gcc_name);
+ return FALSE;
+ }
+ }
+
+ /* lto-wrapper should be in the same directory with LTO plugin. */
+ wrapper_name = bfd_malloc (length + sizeof (LTO_WRAPPER_EXECUTABLE));
+ if (wrapper_name == NULL)
+ {
+ free (gcc_name);
+ return FALSE;
+ }
+ memcpy (wrapper_name, real_name, length);
+ memcpy (wrapper_name + length, LTO_WRAPPER_EXECUTABLE,
+ sizeof (LTO_WRAPPER_EXECUTABLE));
+ if (stat (wrapper_name, &st) == 0 && S_ISREG (st.st_mode))
+ {
+ resolution_file = make_temp_file (".res");
+ if (resolution_file)
+ {
+ plugin->gcc = gcc_name;
+ plugin->lto_wrapper = wrapper_name;
+ plugin->gcc_env = concat ("COLLECT_GCC=", gcc_name, NULL);
+ plugin->resolution_file = resolution_file;
+ plugin->resolution_option = concat ("-fresolution=",
+ resolution_file, NULL);
+ return TRUE;
+ }
+ }
+
+ free (gcc_name);
+ free (wrapper_name);
+ return FALSE;
+}
+
+/* Set environment variables for GCC LTO wrapper to covert LTO IR
+ object to the real object. */
+
+static int
+setup_lto_wrapper_env (struct plugin_list_entry *plugin)
+{
+ return (putenv (plugin->gcc_env)
+ || putenv ("COLLECT_GCC_OPTIONS="));
+}
+
+static struct plugin_list_entry *plugin_list = NULL;
+static struct plugin_list_entry *current_plugin = NULL;
+