/* Load up and initialise all plugins after argument parsing. */ int plugin_load_plugins (void) { struct ld_plugin_tv *my_tv; unsigned int max_args = 0; plugin_t *curplug = plugins_list; /* If there are no plugins, we need do nothing this run. */ if (!curplug) return 0; /* First pass over plugins to find max # args needed so that we can size and allocate the tv array. */ while (curplug) { if (curplug->n_args > max_args) max_args = curplug->n_args; curplug = curplug->next; } /* Allocate tv array and initialise constant part. */ my_tv = xmalloc ((max_args + 1 + tv_header_size) * sizeof *my_tv); set_tv_header (my_tv); /* Pass over plugins again, activating them. */ curplug = plugins_list; while (curplug) { enum ld_plugin_status rv; ld_plugin_onload onloadfn = dlsym (curplug->dlhandle, "onload"); if (!onloadfn) onloadfn = dlsym (curplug->dlhandle, "_onload"); if (!onloadfn) return set_plugin_error (curplug->name); set_tv_plugin_args (curplug, &my_tv[tv_header_size]); called_plugin = curplug; rv = (*onloadfn) (my_tv); called_plugin = NULL; if (rv != LDPS_OK) return set_plugin_error (curplug->name); curplug = curplug->next; } /* Since plugin(s) inited ok, assume they're going to want symbol resolutions, which needs us to track which symbols are referenced by non-IR files using the linker's notice callback. */ orig_notice_all = link_info.notice_all; orig_callbacks = link_info.callbacks; plugin_callbacks = *orig_callbacks; plugin_callbacks.notice = &plugin_notice; link_info.notice_all = TRUE; link_info.callbacks = &plugin_callbacks; return 0; }
/* Accumulate option arguments for last-loaded plugin, or return error if none. */ int plugin_opt_plugin_arg (const char *arg) { plugin_arg_t *newarg; if (!last_plugin) return set_plugin_error (_("<no plugin>")); /* Ignore -pass-through= from GCC driver. */ if (*arg == '-') { const char *p = arg + 1; if (*p == '-') ++p; if (strncmp (p, "pass-through=", 13) == 0) return 0; } newarg = xmalloc (sizeof *newarg); newarg->arg = arg; newarg->next = NULL; /* Chain on end to preserve command-line order. */ *last_plugin_args_tail_chain_ptr = newarg; last_plugin_args_tail_chain_ptr = &newarg->next; last_plugin->n_args++; return 0; }
/* Call 'claim file' hook for all plugins. */ static int plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) { plugin_t *curplug = plugins_list; *claimed = FALSE; while (curplug && !*claimed) { if (curplug->claim_file_handler) { off_t cur_offset; enum ld_plugin_status rv; called_plugin = curplug; cur_offset = lseek (file->fd, 0, SEEK_CUR); rv = (*curplug->claim_file_handler) (file, claimed); if (!*claimed) lseek (file->fd, cur_offset, SEEK_SET); called_plugin = NULL; if (rv != LDPS_OK) set_plugin_error (curplug->name); } curplug = curplug->next; } return plugin_error_p () ? -1 : 0; }
/* Accumulate option arguments for last-loaded plugin, or return error if none. */ int plugin_opt_plugin_arg (const char *arg) { plugin_arg_t *newarg; if (!last_plugin) return set_plugin_error (_("<no plugin>")); newarg = xmalloc (sizeof *newarg); newarg->arg = arg; newarg->next = NULL; /* Chain on end to preserve command-line order. */ *last_plugin_args_tail_chain_ptr = newarg; last_plugin_args_tail_chain_ptr = &newarg->next; last_plugin->n_args++; return 0; }
/* Call 'claim file' hook for all plugins. */ static int plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) { plugin_t *curplug = plugins_list; *claimed = FALSE; while (curplug && !*claimed) { if (curplug->claim_file_handler) { enum ld_plugin_status rv; called_plugin = curplug; rv = (*curplug->claim_file_handler) (file, claimed); called_plugin = NULL; if (rv != LDPS_OK) set_plugin_error (curplug->name); } curplug = curplug->next; } return plugin_error_p () ? -1 : 0; }
/* Handle -plugin arg: find and load plugin, or return error. */ int plugin_opt_plugin (const char *plugin) { plugin_t *newplug; newplug = xmalloc (sizeof *newplug); memset (newplug, 0, sizeof *newplug); newplug->name = plugin; newplug->dlhandle = dlopen (plugin, RTLD_NOW); if (!newplug->dlhandle) return set_plugin_error (plugin); /* Chain on end, so when we run list it is in command-line order. */ *plugins_tail_chain_ptr = newplug; plugins_tail_chain_ptr = &newplug->next; /* Record it as current plugin for receiving args. */ last_plugin = newplug; last_plugin_args_tail_chain_ptr = &newplug->args; return 0; }
/* Call 'cleanup' hook for all plugins at exit. */ void plugin_call_cleanup (void) { plugin_t *curplug = plugins_list; while (curplug) { if (curplug->cleanup_handler && !curplug->cleanup_done) { enum ld_plugin_status rv; curplug->cleanup_done = TRUE; called_plugin = curplug; rv = (*curplug->cleanup_handler) (); called_plugin = NULL; if (rv != LDPS_OK) set_plugin_error (curplug->name); dlclose (curplug->dlhandle); } curplug = curplug->next; } if (plugin_error_p ()) info_msg (_("%P: %s: error in plugin cleanup (ignored)\n"), plugin_error_plugin ()); }
/* Call 'all symbols read' hook for all plugins. */ int plugin_call_all_symbols_read (void) { plugin_t *curplug = plugins_list; /* Disable any further file-claiming. */ no_more_claiming = TRUE; while (curplug) { if (curplug->all_symbols_read_handler) { enum ld_plugin_status rv; called_plugin = curplug; rv = (*curplug->all_symbols_read_handler) (); called_plugin = NULL; if (rv != LDPS_OK) set_plugin_error (curplug->name); } curplug = curplug->next; } return plugin_error_p () ? -1 : 0; }