X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fplugin.c;h=1c737a5cd254b13e18d0cd3641820f5a69cc6398;hp=95297a7d395f4fd14e8152d1af47d959cb415d07;hb=a5fe80bda946d6ee8023587c37963d8b6612a730;hpb=e16288b4a39e53823d38ca7b17f97be364101d55 diff --git a/gcc/plugin.c b/gcc/plugin.c index 95297a7d395..1c737a5cd25 100644 --- a/gcc/plugin.c +++ b/gcc/plugin.c @@ -1,5 +1,5 @@ /* Support for GCC plugin mechanism. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see /* If plugin support is not enabled, do not try to execute any code that may reference libdl. The generic code is still compiled in to - avoid including to many conditional compilation paths in the rest + avoid including too many conditional compilation paths in the rest of the compiler. */ #ifdef ENABLE_PLUGIN #include @@ -38,30 +38,36 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "plugin.h" #include "timevar.h" +#include "ggc.h" + +#ifdef ENABLE_PLUGIN +#include "plugin-version.h" +#endif + +#define GCC_PLUGIN_STRINGIFY0(X) #X +#define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X) /* Event names as strings. Keep in sync with enum plugin_event. */ -const char *plugin_event_name[] = +static const char *plugin_event_name_init[] = { - "PLUGIN_PASS_MANAGER_SETUP", - "PLUGIN_FINISH_TYPE", - "PLUGIN_FINISH_UNIT", - "PLUGIN_CXX_CP_PRE_GENERICIZE", - "PLUGIN_FINISH", - "PLUGIN_INFO", - "PLUGIN_EVENT_LAST" +# define DEFEVENT(NAME) GCC_PLUGIN_STRINGIFY1 (NAME), +# include "plugin.def" +# undef DEFEVENT }; -/* Object that keeps track of the plugin name and its arguments - when parsing the command-line options -fplugin=/path/to/NAME.so and - -fplugin-arg-NAME-[=]. */ -struct plugin_name_args -{ - char *base_name; - const char *full_name; - int argc; - struct plugin_argument *argv; - const char *version; -}; +/* A printf format large enough for the largest event above. */ +#define FMT_FOR_PLUGIN_EVENT "%-32s" + +const char **plugin_event_name = plugin_event_name_init; + +/* A hash table to map event names to the position of the names in the + plugin_event_name table. */ +static htab_t event_tab; + +/* Keep track of the limit of allocated events and space ready for + allocating events. */ +static int event_last = PLUGIN_EVENT_FIRST_DYNAMIC; +static int event_horizon = PLUGIN_EVENT_FIRST_DYNAMIC; /* Hash table for the plugin_name_args objects created during command-line parsing. */ @@ -77,27 +83,20 @@ struct callback_info }; /* An array of lists of 'callback_info' objects indexed by the event id. */ -static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL }; - -/* List node for an inserted pass instance. We need to keep track of all - the newly-added pass instances (with 'added_pass_nodes' defined below) - so that we can register their dump files after pass-positioning is finished. - Registering dumping files needs to be post-processed or the - static_pass_number of the opt_pass object would be modified and mess up - the dump file names of future pass instances to be added. */ -struct pass_list_node -{ - struct opt_pass *pass; - struct pass_list_node *next; -}; +static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_FIRST_DYNAMIC]; +static struct callback_info **plugin_callbacks = plugin_callbacks_init; -static struct pass_list_node *added_pass_nodes = NULL; -static struct pass_list_node *prev_added_pass_node; +/* For invoke_plugin_callbacks(), see plugin.h. */ +bool flag_plugin_added = false; #ifdef ENABLE_PLUGIN /* Each plugin should define an initialization function with exactly this name. */ static const char *str_plugin_init_func_name = "plugin_init"; + +/* Each plugin should define this symbol to assert that it is + distributed under a GPL-compatible license. */ +static const char *str_license = "plugin_is_GPL_compatible"; #endif /* Helper function for the hash table that compares the base_name of the @@ -127,18 +126,45 @@ get_plugin_base_name (const char *full_name) } -/* Create a plugin_name_args object for the give plugin and insert it to - the hash table. This function is called when -fplugin=/path/to/NAME.so - option is processed. */ +/* Create a plugin_name_args object for the given plugin and insert it + to the hash table. This function is called when + -fplugin=/path/to/NAME.so or -fplugin=NAME option is processed. */ void add_new_plugin (const char* plugin_name) { struct plugin_name_args *plugin; void **slot; - char *base_name = get_plugin_base_name (plugin_name); + char *base_name; + bool name_is_short; + const char *pc; + + flag_plugin_added = true; + + /* Replace short names by their full path when relevant. */ + name_is_short = !IS_ABSOLUTE_PATH (plugin_name); + for (pc = plugin_name; name_is_short && *pc; pc++) + if (*pc == '.' || IS_DIR_SEPARATOR (*pc)) + name_is_short = false; + + if (name_is_short) + { + base_name = CONST_CAST (char*, plugin_name); + /* FIXME: the ".so" suffix is currently builtin, since plugins + only work on ELF host systems like e.g. Linux or Solaris. + When plugins shall be available on non ELF systems such as + Windows or MacOS, this code has to be greatly improved. */ + plugin_name = concat (default_plugin_dir_name (), "/", + plugin_name, ".so", NULL); + if (access (plugin_name, R_OK)) + fatal_error + ("inacessible plugin file %s expanded from short plugin name %s: %m", + plugin_name, base_name); + } + else + base_name = get_plugin_base_name (plugin_name); - /* If this is the first -fplugin= option we encounter, create + /* If this is the first -fplugin= option we encounter, create 'plugin_name_args_tab' hash table. */ if (!plugin_name_args_tab) plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq, @@ -284,183 +310,81 @@ parse_plugin_arg_opt (const char *arg) XDELETEVEC (name); } +/* Register additional plugin information. NAME is the name passed to + plugin_init. INFO is the information that should be registered. */ -/* Insert the plugin pass at the proper position. Return true if the pass - is successfully added. - - PLUGIN_PASS_INFO - new pass to be inserted - PASS_LIST - root of the pass list to insert the new pass to */ - -static bool -position_pass (struct plugin_pass *plugin_pass_info, - struct opt_pass **pass_list) +static void +register_plugin_info (const char* name, struct plugin_info *info) { - struct opt_pass *pass = *pass_list, *prev_pass = NULL; - bool success = false; - - for ( ; pass; prev_pass = pass, pass = pass->next) - { - /* Check if the current pass is of the same type as the new pass and - matches the name and the instance number of the reference pass. */ - if (pass->type == plugin_pass_info->pass->type - && pass->name - && !strcmp (pass->name, plugin_pass_info->reference_pass_name) - && ((plugin_pass_info->ref_pass_instance_number == 0) - || (plugin_pass_info->ref_pass_instance_number == - pass->static_pass_number) - || (plugin_pass_info->ref_pass_instance_number == 1 - && pass->todo_flags_start & TODO_mark_first_instance))) - { - struct opt_pass *new_pass = plugin_pass_info->pass; - struct pass_list_node *new_pass_node; - - /* The following code (if-statement) is adopted from next_pass_1. */ - if (new_pass->static_pass_number) - { - new_pass = XNEW (struct opt_pass); - memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass)); - new_pass->next = NULL; - - new_pass->todo_flags_start &= ~TODO_mark_first_instance; - - plugin_pass_info->pass->static_pass_number -= 1; - new_pass->static_pass_number = - -plugin_pass_info->pass->static_pass_number; - } - else - { - new_pass->todo_flags_start |= TODO_mark_first_instance; - new_pass->static_pass_number = -1; - } - - /* Insert the new pass instance based on the positioning op. */ - switch (plugin_pass_info->pos_op) - { - case PASS_POS_INSERT_AFTER: - new_pass->next = pass->next; - pass->next = new_pass; - break; - case PASS_POS_INSERT_BEFORE: - new_pass->next = pass; - if (prev_pass) - prev_pass->next = new_pass; - else - *pass_list = new_pass; - break; - case PASS_POS_REPLACE: - new_pass->next = pass->next; - if (prev_pass) - prev_pass->next = new_pass; - else - *pass_list = new_pass; - new_pass->sub = pass->sub; - new_pass->tv_id = pass->tv_id; - pass = new_pass; - break; - default: - error ("Invalid pass positioning operation"); - return false; - } - - /* Save the newly added pass (instance) in the added_pass_nodes - list so that we can register its dump file later. Note that - we cannot register the dump file now because doing so will modify - the static_pass_number of the opt_pass object and therefore - mess up the dump file name of future instances. */ - new_pass_node = XCNEW (struct pass_list_node); - new_pass_node->pass = new_pass; - if (!added_pass_nodes) - added_pass_nodes = new_pass_node; - else - prev_added_pass_node->next = new_pass_node; - prev_added_pass_node = new_pass_node; - - success = true; - } - - if (pass->sub && position_pass (plugin_pass_info, &pass->sub)) - success = true; - } - - return success; + void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT); + struct plugin_name_args *plugin = (struct plugin_name_args *) *slot; + plugin->version = info->version; + plugin->help = info->help; } +/* Helper function for the event hash table that compares the name of an + existing entry (E1) with the given string (S2). */ -/* Hook into the pass lists (trees) a new pass registered by a plugin. +static int +htab_event_eq (const void *e1, const void *s2) +{ + const char *s1= *(const char * const *) e1; + return !strcmp (s1, (const char *) s2); +} - PLUGIN_NAME - display name for the plugin - PASS_INFO - plugin pass information that specifies the opt_pass object, - reference pass, instance number, and how to position - the pass */ +/* Look up the event id for NAME. If the name is not found, return -1 + if INSERT is NO_INSERT. */ -static void -register_pass (const char *plugin_name, struct plugin_pass *pass_info) +int +get_named_event_id (const char *name, enum insert_option insert) { - if (!pass_info->pass) - { - error ("No pass specified when registering a new pass in plugin %s", - plugin_name); - return; - } + void **slot; - if (!pass_info->reference_pass_name) + if (!event_tab) { - error ("No reference pass specified for positioning the pass " - " from plugin %s", plugin_name); - return; + int i; + + event_tab = htab_create (150, htab_hash_string, htab_event_eq, NULL); + for (i = 0; i < event_last; i++) + { + slot = htab_find_slot (event_tab, plugin_event_name[i], INSERT); + gcc_assert (*slot == HTAB_EMPTY_ENTRY); + *slot = &plugin_event_name[i]; + } } + slot = htab_find_slot (event_tab, name, insert); + if (slot == NULL) + return -1; + if (*slot != HTAB_EMPTY_ENTRY) + return (const char **) *slot - &plugin_event_name[0]; - /* Try to insert the new pass to the pass lists. We need to check all - three lists as the reference pass could be in one (or all) of them. */ - if (!position_pass (pass_info, &all_lowering_passes) - && !position_pass (pass_info, &all_ipa_passes) - && !position_pass (pass_info, &all_passes)) - error ("Failed to position pass %s registered by plugin %s. " - "Cannot find the (specified instance of) reference pass %s", - pass_info->pass->name, plugin_name, pass_info->reference_pass_name); - else + if (event_last >= event_horizon) { - /* OK, we have successfully inserted the new pass. We need to register - the dump files for the newly added pass and its duplicates (if any). - Because the registration of plugin passes happens after the - command-line options are parsed, the options that specify single - pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new - plugin passes. Therefore we currently can only enable dumping of - new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all) - are specified. While doing so, we also delete the pass_list_node - objects created during pass positioning. */ - while (added_pass_nodes) - { - struct pass_list_node *next_node = added_pass_nodes->next; - enum tree_dump_index tdi; - register_one_dump_file (added_pass_nodes->pass); - if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS - || added_pass_nodes->pass->type == IPA_PASS) - tdi = TDI_ipa_all; - else if (added_pass_nodes->pass->type == GIMPLE_PASS) - tdi = TDI_tree_all; - else - tdi = TDI_rtl_all; - /* Check if dump-all flag is specified. */ - if (get_dump_file_info (tdi)->state) - get_dump_file_info (added_pass_nodes->pass->static_pass_number) - ->state = get_dump_file_info (tdi)->state; - XDELETE (added_pass_nodes); - added_pass_nodes = next_node; - } + event_horizon = event_last * 2; + if (plugin_event_name == plugin_event_name_init) + { + plugin_event_name = XNEWVEC (const char *, event_horizon); + memcpy (plugin_event_name, plugin_event_name_init, + sizeof plugin_event_name_init); + plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon); + memcpy (plugin_callbacks, plugin_callbacks_init, + sizeof plugin_callbacks_init); + } + else + { + plugin_event_name + = XRESIZEVEC (const char *, plugin_event_name, event_horizon); + plugin_callbacks = XRESIZEVEC (struct callback_info *, + plugin_callbacks, event_horizon); + } + /* All the pointers in the hash table will need to be updated. */ + htab_delete (event_tab); + event_tab = NULL; } -} - - -/* Register additional plugin information. NAME is the name passed to - plugin_init. INFO is the information that should be registered. */ - -static void -register_plugin_info (const char* name, struct plugin_info *info) -{ - void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT); - struct plugin_name_args *plugin = (struct plugin_name_args *) *slot; - plugin->version = info->version; + else + *slot = &plugin_event_name[event_last]; + plugin_event_name[event_last] = name; + return event_last++; } /* Called from the plugin's initialization code. Register a single callback. @@ -473,22 +397,56 @@ register_plugin_info (const char* name, struct plugin_info *info) void register_callback (const char *plugin_name, - enum plugin_event event, + int event, plugin_callback_func callback, void *user_data) { switch (event) { case PLUGIN_PASS_MANAGER_SETUP: - register_pass (plugin_name, (struct plugin_pass *) user_data); + gcc_assert (!callback); + register_pass ((struct register_pass_info *) user_data); break; case PLUGIN_INFO: + gcc_assert (!callback); register_plugin_info (plugin_name, (struct plugin_info *) user_data); break; + case PLUGIN_REGISTER_GGC_ROOTS: + gcc_assert (!callback); + ggc_register_root_tab ((const struct ggc_root_tab*) user_data); + break; + case PLUGIN_REGISTER_GGC_CACHES: + gcc_assert (!callback); + ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data); + break; + case PLUGIN_EVENT_FIRST_DYNAMIC: + default: + if (event < PLUGIN_EVENT_FIRST_DYNAMIC || event >= event_last) + { + error ("Unknown callback event registered by plugin %s", + plugin_name); + return; + } + /* Fall through. */ case PLUGIN_FINISH_TYPE: + case PLUGIN_START_UNIT: case PLUGIN_FINISH_UNIT: - case PLUGIN_CXX_CP_PRE_GENERICIZE: + case PLUGIN_PRE_GENERICIZE: + case PLUGIN_GGC_START: + case PLUGIN_GGC_MARKING: + case PLUGIN_GGC_END: + case PLUGIN_ATTRIBUTES: + case PLUGIN_PRAGMAS: case PLUGIN_FINISH: + case PLUGIN_ALL_PASSES_START: + case PLUGIN_ALL_PASSES_END: + case PLUGIN_ALL_IPA_PASSES_START: + case PLUGIN_ALL_IPA_PASSES_END: + case PLUGIN_OVERRIDE_GATE: + case PLUGIN_PASS_EXECUTION: + case PLUGIN_EARLY_GIMPLE_PASSES_START: + case PLUGIN_EARLY_GIMPLE_PASSES_END: + case PLUGIN_NEW_PASS: { struct callback_info *new_callback; if (!callback) @@ -505,47 +463,86 @@ register_callback (const char *plugin_name, plugin_callbacks[event] = new_callback; } break; - case PLUGIN_EVENT_LAST: - default: - error ("Unkown callback event registered by plugin %s", - plugin_name); } } +/* Remove a callback for EVENT which has been registered with for a plugin + PLUGIN_NAME. Return PLUGEVT_SUCCESS if a matching callback was + found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching + callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid. */ +int +unregister_callback (const char *plugin_name, int event) +{ + struct callback_info *callback, **cbp; + + if (event >= event_last) + return PLUGEVT_NO_SUCH_EVENT; -/* Called from inside GCC. Invoke all plug-in callbacks registered with - the specified event. + for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next) + if (strcmp (callback->plugin_name, plugin_name) == 0) + { + *cbp = callback->next; + return PLUGEVT_SUCCESS; + } + return PLUGEVT_NO_CALLBACK; +} - EVENT - the event identifier - GCC_DATA - event-specific data provided by the compiler */ +/* Invoke all plugin callbacks registered with the specified event, + called from invoke_plugin_callbacks(). */ -void -invoke_plugin_callbacks (enum plugin_event event, void *gcc_data) +int +invoke_plugin_callbacks_full (int event, void *gcc_data) { + int retval = PLUGEVT_SUCCESS; + timevar_push (TV_PLUGIN_RUN); switch (event) { + case PLUGIN_EVENT_FIRST_DYNAMIC: + default: + gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC); + gcc_assert (event < event_last); + /* Fall through. */ case PLUGIN_FINISH_TYPE: + case PLUGIN_START_UNIT: case PLUGIN_FINISH_UNIT: - case PLUGIN_CXX_CP_PRE_GENERICIZE: + case PLUGIN_PRE_GENERICIZE: + case PLUGIN_ATTRIBUTES: + case PLUGIN_PRAGMAS: case PLUGIN_FINISH: + case PLUGIN_GGC_START: + case PLUGIN_GGC_MARKING: + case PLUGIN_GGC_END: + case PLUGIN_ALL_PASSES_START: + case PLUGIN_ALL_PASSES_END: + case PLUGIN_ALL_IPA_PASSES_START: + case PLUGIN_ALL_IPA_PASSES_END: + case PLUGIN_OVERRIDE_GATE: + case PLUGIN_PASS_EXECUTION: + case PLUGIN_EARLY_GIMPLE_PASSES_START: + case PLUGIN_EARLY_GIMPLE_PASSES_END: + case PLUGIN_NEW_PASS: { /* Iterate over every callback registered with this event and call it. */ struct callback_info *callback = plugin_callbacks[event]; + + if (!callback) + retval = PLUGEVT_NO_CALLBACK; for ( ; callback; callback = callback->next) (*callback->func) (gcc_data, callback->user_data); } break; case PLUGIN_PASS_MANAGER_SETUP: - case PLUGIN_EVENT_LAST: - default: + case PLUGIN_REGISTER_GGC_ROOTS: + case PLUGIN_REGISTER_GGC_CACHES: gcc_assert (false); } timevar_pop (TV_PLUGIN_RUN); + return retval; } #ifdef ENABLE_PLUGIN @@ -564,10 +561,14 @@ try_init_one_plugin (struct plugin_name_args *plugin) { void *dl_handle; plugin_init_func plugin_init; - char *err; + const char *err; PTR_UNION_TYPE (plugin_init_func) plugin_init_union; - dl_handle = dlopen (plugin->full_name, RTLD_NOW); + /* We use RTLD_NOW to accelerate binding and detect any mismatch + between the API expected by the plugin and the GCC API; we use + RTLD_GLOBAL which is useful to plugins which themselves call + dlopen. */ + dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL); if (!dl_handle) { error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ()); @@ -577,6 +578,11 @@ try_init_one_plugin (struct plugin_name_args *plugin) /* Clear any existing error. */ dlerror (); + /* Check the plugin license. */ + if (dlsym (dl_handle, str_license) == NULL) + fatal_error ("plugin %s is not licensed under a GPL-compatible license\n" + "%s", plugin->full_name, dlerror ()); + PTR_UNION_AS_VOID_PTR (plugin_init_union) = dlsym (dl_handle, str_plugin_init_func_name); plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union); @@ -589,7 +595,7 @@ try_init_one_plugin (struct plugin_name_args *plugin) } /* Call the plugin-provided initialization routine with the arguments. */ - if ((*plugin_init) (plugin->base_name, plugin->argc, plugin->argv)) + if ((*plugin_init) (plugin, &gcc_version)) { error ("Fail to initialize plugin %s", plugin->full_name); return false; @@ -633,7 +639,7 @@ initialize_plugins (void) return; timevar_push (TV_PLUGIN_INIT); - + #ifdef ENABLE_PLUGIN /* Traverse and initialize each plugin specified in the command-line. */ htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL); @@ -708,15 +714,60 @@ print_plugins_versions (FILE *file, const char *indent) htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt); } +/* Print help for one plugin. SLOT is the hash table slot. DATA is the + argument to htab_traverse_noresize. */ + +static int +print_help_one_plugin (void **slot, void *data) +{ + struct print_options *opt = (struct print_options *) data; + struct plugin_name_args *plugin = (struct plugin_name_args *) *slot; + const char *help = plugin->help ? plugin->help : "No help available ."; + + char *dup = xstrdup (help); + char *p, *nl; + fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name); + + for (p = nl = dup; nl; p = nl) + { + nl = strchr (nl, '\n'); + if (nl) + { + *nl = '\0'; + nl++; + } + fprintf (opt->file, " %s %s\n", opt->indent, p); + } + + free (dup); + return 1; +} + +/* Print help for each plugin. The output goes to FILE and every line starts + with INDENT. */ + +void +print_plugins_help (FILE *file, const char *indent) +{ + struct print_options opt; + opt.file = file; + opt.indent = indent; + if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0) + return; + + fprintf (file, "%sHelp for the loaded plugins:\n", indent); + htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt); +} + /* Return true if plugins have been loaded. */ bool plugins_active_p (void) { - enum plugin_event event; + int event; - for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++) + for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++) if (plugin_callbacks[event]) return true; @@ -730,23 +781,23 @@ plugins_active_p (void) void dump_active_plugins (FILE *file) { - enum plugin_event event; + int event; if (!plugins_active_p ()) return; - fprintf (stderr, "Event\t\t\tPlugins\n"); - for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++) + fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins")); + for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++) if (plugin_callbacks[event]) { struct callback_info *ci; - fprintf (file, "%s\t", plugin_event_name[event]); + fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]); for (ci = plugin_callbacks[event]; ci; ci = ci->next) - fprintf (file, "%s ", ci->plugin_name); + fprintf (file, " %s", ci->plugin_name); - fprintf (file, "\n"); + putc('\n', file); } } @@ -758,3 +809,75 @@ debug_active_plugins (void) { dump_active_plugins (stderr); } + +/* Give a warning if plugins are present, before an ICE message asking + to submit a bug report. */ + +void +warn_if_plugins (void) +{ + if (plugins_active_p ()) + { + fnotice (stderr, "*** WARNING *** there are active plugins, do not report" + " this as a bug unless you can reproduce it without enabling" + " any plugins.\n"); + dump_active_plugins (stderr); + } + +} + +/* Likewise, as a callback from the diagnostics code. */ + +void +plugins_internal_error_function (struct diagnostic_context *context ATTRIBUTE_UNUSED, + const char *msgid ATTRIBUTE_UNUSED, + va_list *ap ATTRIBUTE_UNUSED) +{ + warn_if_plugins (); +} + +/* The default version check. Compares every field in VERSION. */ + +bool +plugin_default_version_check (struct plugin_gcc_version *gcc_version, + struct plugin_gcc_version *plugin_version) +{ + if (!gcc_version || !plugin_version) + return false; + + if (strcmp (gcc_version->basever, plugin_version->basever)) + return false; + if (strcmp (gcc_version->datestamp, plugin_version->datestamp)) + return false; + if (strcmp (gcc_version->devphase, plugin_version->devphase)) + return false; + if (strcmp (gcc_version->revision, plugin_version->revision)) + return false; + if (strcmp (gcc_version->configuration_arguments, + plugin_version->configuration_arguments)) + return false; + return true; +} + + +/* Return the current value of event_last, so that plugins which provide + additional functionality for events for the benefit of high-level plugins + know how many valid entries plugin_event_name holds. */ + +int +get_event_last (void) +{ + return event_last; +} + + +/* Retrieve the default plugin directory. The gcc driver should have passed + it as -iplugindir to the cc1 program, and it is queriable thru the + -print-file-name=plugin option to gcc. */ +const char* +default_plugin_dir_name (void) +{ + if (!plugindir_string) + fatal_error ("-iplugindir option not passed from the gcc driver"); + return plugindir_string; +}