/* 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 <dlfcn.h>
#include "intl.h"
#include "plugin.h"
#include "timevar.h"
+#include "ggc.h"
+
#ifdef ENABLE_PLUGIN
#include "plugin-version.h"
#endif
"PLUGIN_CXX_CP_PRE_GENERICIZE",
"PLUGIN_FINISH",
"PLUGIN_INFO",
+ "PLUGIN_GGC_START",
+ "PLUGIN_GGC_MARKING",
+ "PLUGIN_GGC_END",
+ "PLUGIN_REGISTER_GGC_ROOTS",
+ "PLUGIN_START_UNIT",
"PLUGIN_EVENT_LAST"
};
-/* 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-<key>[=<value>]. */
-struct plugin_name_args
-{
- char *base_name;
- const char *full_name;
- int argc;
- struct plugin_argument *argv;
- const char *version;
- const char *help;
-};
-
/* Hash table for the plugin_name_args objects created during command-line
parsing. */
static htab_t plugin_name_args_tab = NULL;
/* 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
case PASS_POS_INSERT_AFTER:
new_pass->next = pass->next;
pass->next = new_pass;
+
+ /* Skip newly inserted pass to avoid repeated
+ insertions in the case where the new pass and the
+ existing one have the same name. */
+ pass = new_pass;
break;
case PASS_POS_INSERT_BEFORE:
new_pass->next = pass;
switch (event)
{
case PLUGIN_PASS_MANAGER_SETUP:
+ gcc_assert (!callback);
register_pass (plugin_name, (struct plugin_pass *) 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_FINISH_TYPE:
+ case PLUGIN_START_UNIT:
case PLUGIN_FINISH_UNIT:
case PLUGIN_CXX_CP_PRE_GENERICIZE:
+ case PLUGIN_GGC_START:
+ case PLUGIN_GGC_MARKING:
+ case PLUGIN_GGC_END:
case PLUGIN_ATTRIBUTES:
case PLUGIN_FINISH:
{
switch (event)
{
case PLUGIN_FINISH_TYPE:
+ case PLUGIN_START_UNIT:
case PLUGIN_FINISH_UNIT:
case PLUGIN_CXX_CP_PRE_GENERICIZE:
case PLUGIN_ATTRIBUTES:
case PLUGIN_FINISH:
+ case PLUGIN_GGC_START:
+ case PLUGIN_GGC_MARKING:
+ case PLUGIN_GGC_END:
{
/* Iterate over every callback registered with this event and
call it. */
case PLUGIN_PASS_MANAGER_SETUP:
case PLUGIN_EVENT_LAST:
+ case PLUGIN_REGISTER_GGC_ROOTS:
default:
gcc_assert (false);
}
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 ());
/* 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);
}
/* Call the plugin-provided initialization routine with the arguments. */
- if ((*plugin_init) (plugin->base_name, &gcc_version, plugin->argc,
- plugin->argv))
+ if ((*plugin_init) (plugin, &gcc_version))
{
error ("Fail to initialize plugin %s", plugin->full_name);
return false;