1 /* Support for GCC plugin mechanism.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* This file contains the support for GCC plugin mechanism based on the
21 APIs described in doc/plugin.texi. */
26 /* If plugin support is not enabled, do not try to execute any code
27 that may reference libdl. The generic code is still compiled in to
28 avoid including to many conditional compilation paths in the rest
34 #include "coretypes.h"
37 #include "tree-pass.h"
42 /* Event names as strings. Keep in sync with enum plugin_event. */
43 const char *plugin_event_name[] =
45 "PLUGIN_PASS_MANAGER_SETUP",
48 "PLUGIN_CXX_CP_PRE_GENERICIZE",
54 /* Object that keeps track of the plugin name and its arguments
55 when parsing the command-line options -fplugin=/path/to/NAME.so and
56 -fplugin-arg-NAME-<key>[=<value>]. */
57 struct plugin_name_args
60 const char *full_name;
62 struct plugin_argument *argv;
66 /* Hash table for the plugin_name_args objects created during command-line
68 static htab_t plugin_name_args_tab = NULL;
70 /* List node for keeping track of plugin-registered callback. */
73 const char *plugin_name; /* Name of plugin that registers the callback. */
74 plugin_callback_func func; /* Callback to be called. */
75 void *user_data; /* plugin-specified data. */
76 struct callback_info *next;
79 /* An array of lists of 'callback_info' objects indexed by the event id. */
80 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
82 /* List node for an inserted pass instance. We need to keep track of all
83 the newly-added pass instances (with 'added_pass_nodes' defined below)
84 so that we can register their dump files after pass-positioning is finished.
85 Registering dumping files needs to be post-processed or the
86 static_pass_number of the opt_pass object would be modified and mess up
87 the dump file names of future pass instances to be added. */
90 struct opt_pass *pass;
91 struct pass_list_node *next;
94 static struct pass_list_node *added_pass_nodes = NULL;
95 static struct pass_list_node *prev_added_pass_node;
98 /* Each plugin should define an initialization function with exactly
100 static const char *str_plugin_init_func_name = "plugin_init";
103 /* Helper function for the hash table that compares the base_name of the
104 existing entry (S1) with the given string (S2). */
107 htab_str_eq (const void *s1, const void *s2)
109 const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
110 return !strcmp (plugin->base_name, (const char *) s2);
114 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
118 get_plugin_base_name (const char *full_name)
120 /* First get the base name part of the full-path name, i.e. NAME.so. */
121 char *base_name = xstrdup (lbasename (full_name));
123 /* Then get rid of '.so' part of the name. */
124 strip_off_ending (base_name, strlen (base_name));
130 /* Create a plugin_name_args object for the give plugin and insert it to
131 the hash table. This function is called when -fplugin=/path/to/NAME.so
132 option is processed. */
135 add_new_plugin (const char* plugin_name)
137 struct plugin_name_args *plugin;
139 char *base_name = get_plugin_base_name (plugin_name);
141 /* If this is the first -fplugin= option we encounter, create
142 'plugin_name_args_tab' hash table. */
143 if (!plugin_name_args_tab)
144 plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
147 slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
149 /* If the same plugin (name) has been specified earlier, either emit an
150 error or a warning message depending on if they have identical full
154 plugin = (struct plugin_name_args *) *slot;
155 if (strcmp (plugin->full_name, plugin_name))
156 error ("Plugin %s was specified with different paths:\n%s\n%s",
157 plugin->base_name, plugin->full_name, plugin_name);
161 plugin = XCNEW (struct plugin_name_args);
162 plugin->base_name = base_name;
163 plugin->full_name = plugin_name;
169 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
170 'plugin_argument' object for the parsed key-value pair. ARG is
171 the <name>-<key>[=<value>] part of the option. */
174 parse_plugin_arg_opt (const char *arg)
176 size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
177 const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
178 char *name, *key, *value;
180 bool name_parsed = false, key_parsed = false;
182 /* Iterate over the ARG string and identify the starting character position
183 of 'name', 'key', and 'value' and their lengths. */
184 for (ptr = arg; *ptr; ++ptr)
186 /* Only the first '-' encountered is considered a separator between
187 'name' and 'key'. All the subsequent '-'s are considered part of
188 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
189 the plugin name is 'foo' and the key is 'bar-primary-key'. */
190 if (*ptr == '-' && !name_parsed)
198 else if (*ptr == '=')
202 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
208 value_start = ptr + 1;
218 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
223 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
224 Otherwise, it is the VALUE_LEN. */
230 name = XNEWVEC (char, name_len + 1);
231 strncpy (name, name_start, name_len);
232 name[name_len] = '\0';
234 /* Check if the named plugin has already been specified earlier in the
236 if (plugin_name_args_tab
237 && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
240 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
242 key = XNEWVEC (char, key_len + 1);
243 strncpy (key, key_start, key_len);
247 value = XNEWVEC (char, value_len + 1);
248 strncpy (value, value_start, value_len);
249 value[value_len] = '\0';
254 /* Create a plugin_argument object for the parsed key-value pair.
255 If there are already arguments for this plugin, we will need to
256 adjust the argument array size by creating a new array and deleting
257 the old one. If the performance ever becomes an issue, we can
258 change the code by pre-allocating a larger array first. */
259 if (plugin->argc > 0)
261 struct plugin_argument *args = XNEWVEC (struct plugin_argument,
263 memcpy (args, plugin->argv,
264 sizeof (struct plugin_argument) * plugin->argc);
265 XDELETEVEC (plugin->argv);
271 gcc_assert (plugin->argv == NULL);
272 plugin->argv = XNEWVEC (struct plugin_argument, 1);
276 plugin->argv[plugin->argc - 1].key = key;
277 plugin->argv[plugin->argc - 1].value = value;
280 error ("Plugin %s should be specified before -fplugin-arg-%s "
281 "in the command line", name, arg);
283 /* We don't need the plugin's name anymore. Just release it. */
288 /* Insert the plugin pass at the proper position. Return true if the pass
289 is successfully added.
291 PLUGIN_PASS_INFO - new pass to be inserted
292 PASS_LIST - root of the pass list to insert the new pass to */
295 position_pass (struct plugin_pass *plugin_pass_info,
296 struct opt_pass **pass_list)
298 struct opt_pass *pass = *pass_list, *prev_pass = NULL;
299 bool success = false;
301 for ( ; pass; prev_pass = pass, pass = pass->next)
303 /* Check if the current pass is of the same type as the new pass and
304 matches the name and the instance number of the reference pass. */
305 if (pass->type == plugin_pass_info->pass->type
307 && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
308 && ((plugin_pass_info->ref_pass_instance_number == 0)
309 || (plugin_pass_info->ref_pass_instance_number ==
310 pass->static_pass_number)
311 || (plugin_pass_info->ref_pass_instance_number == 1
312 && pass->todo_flags_start & TODO_mark_first_instance)))
314 struct opt_pass *new_pass = plugin_pass_info->pass;
315 struct pass_list_node *new_pass_node;
317 /* The following code (if-statement) is adopted from next_pass_1. */
318 if (new_pass->static_pass_number)
320 new_pass = XNEW (struct opt_pass);
321 memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
322 new_pass->next = NULL;
324 new_pass->todo_flags_start &= ~TODO_mark_first_instance;
326 plugin_pass_info->pass->static_pass_number -= 1;
327 new_pass->static_pass_number =
328 -plugin_pass_info->pass->static_pass_number;
332 new_pass->todo_flags_start |= TODO_mark_first_instance;
333 new_pass->static_pass_number = -1;
336 /* Insert the new pass instance based on the positioning op. */
337 switch (plugin_pass_info->pos_op)
339 case PASS_POS_INSERT_AFTER:
340 new_pass->next = pass->next;
341 pass->next = new_pass;
343 case PASS_POS_INSERT_BEFORE:
344 new_pass->next = pass;
346 prev_pass->next = new_pass;
348 *pass_list = new_pass;
350 case PASS_POS_REPLACE:
351 new_pass->next = pass->next;
353 prev_pass->next = new_pass;
355 *pass_list = new_pass;
356 new_pass->sub = pass->sub;
357 new_pass->tv_id = pass->tv_id;
361 error ("Invalid pass positioning operation");
365 /* Save the newly added pass (instance) in the added_pass_nodes
366 list so that we can register its dump file later. Note that
367 we cannot register the dump file now because doing so will modify
368 the static_pass_number of the opt_pass object and therefore
369 mess up the dump file name of future instances. */
370 new_pass_node = XCNEW (struct pass_list_node);
371 new_pass_node->pass = new_pass;
372 if (!added_pass_nodes)
373 added_pass_nodes = new_pass_node;
375 prev_added_pass_node->next = new_pass_node;
376 prev_added_pass_node = new_pass_node;
381 if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
389 /* Hook into the pass lists (trees) a new pass registered by a plugin.
391 PLUGIN_NAME - display name for the plugin
392 PASS_INFO - plugin pass information that specifies the opt_pass object,
393 reference pass, instance number, and how to position
397 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
399 if (!pass_info->pass)
401 error ("No pass specified when registering a new pass in plugin %s",
406 if (!pass_info->reference_pass_name)
408 error ("No reference pass specified for positioning the pass "
409 " from plugin %s", plugin_name);
413 /* Try to insert the new pass to the pass lists. We need to check all
414 three lists as the reference pass could be in one (or all) of them. */
415 if (!position_pass (pass_info, &all_lowering_passes)
416 && !position_pass (pass_info, &all_ipa_passes)
417 && !position_pass (pass_info, &all_passes))
418 error ("Failed to position pass %s registered by plugin %s. "
419 "Cannot find the (specified instance of) reference pass %s",
420 pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
423 /* OK, we have successfully inserted the new pass. We need to register
424 the dump files for the newly added pass and its duplicates (if any).
425 Because the registration of plugin passes happens after the
426 command-line options are parsed, the options that specify single
427 pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
428 plugin passes. Therefore we currently can only enable dumping of
429 new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
430 are specified. While doing so, we also delete the pass_list_node
431 objects created during pass positioning. */
432 while (added_pass_nodes)
434 struct pass_list_node *next_node = added_pass_nodes->next;
435 enum tree_dump_index tdi;
436 register_one_dump_file (added_pass_nodes->pass);
437 if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
438 || added_pass_nodes->pass->type == IPA_PASS)
440 else if (added_pass_nodes->pass->type == GIMPLE_PASS)
444 /* Check if dump-all flag is specified. */
445 if (get_dump_file_info (tdi)->state)
446 get_dump_file_info (added_pass_nodes->pass->static_pass_number)
447 ->state = get_dump_file_info (tdi)->state;
448 XDELETE (added_pass_nodes);
449 added_pass_nodes = next_node;
455 /* Register additional plugin information. NAME is the name passed to
456 plugin_init. INFO is the information that should be registered. */
459 register_plugin_info (const char* name, struct plugin_info *info)
461 void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
462 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
463 plugin->version = info->version;
466 /* Called from the plugin's initialization code. Register a single callback.
467 This function can be called multiple times.
469 PLUGIN_NAME - display name for this plugin
470 EVENT - which event the callback is for
471 CALLBACK - the callback to be called at the event
472 USER_DATA - plugin-provided data */
475 register_callback (const char *plugin_name,
476 enum plugin_event event,
477 plugin_callback_func callback,
482 case PLUGIN_PASS_MANAGER_SETUP:
483 register_pass (plugin_name, (struct plugin_pass *) user_data);
486 register_plugin_info (plugin_name, (struct plugin_info *) user_data);
488 case PLUGIN_FINISH_TYPE:
489 case PLUGIN_FINISH_UNIT:
490 case PLUGIN_CXX_CP_PRE_GENERICIZE:
493 struct callback_info *new_callback;
496 error ("Plugin %s registered a null callback function "
497 "for event %s", plugin_name, plugin_event_name[event]);
500 new_callback = XNEW (struct callback_info);
501 new_callback->plugin_name = plugin_name;
502 new_callback->func = callback;
503 new_callback->user_data = user_data;
504 new_callback->next = plugin_callbacks[event];
505 plugin_callbacks[event] = new_callback;
508 case PLUGIN_EVENT_LAST:
510 error ("Unkown callback event registered by plugin %s",
516 /* Called from inside GCC. Invoke all plug-in callbacks registered with
519 EVENT - the event identifier
520 GCC_DATA - event-specific data provided by the compiler */
523 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
525 timevar_push (TV_PLUGIN_RUN);
529 case PLUGIN_FINISH_TYPE:
530 case PLUGIN_FINISH_UNIT:
531 case PLUGIN_CXX_CP_PRE_GENERICIZE:
534 /* Iterate over every callback registered with this event and
536 struct callback_info *callback = plugin_callbacks[event];
537 for ( ; callback; callback = callback->next)
538 (*callback->func) (gcc_data, callback->user_data);
542 case PLUGIN_PASS_MANAGER_SETUP:
543 case PLUGIN_EVENT_LAST:
548 timevar_pop (TV_PLUGIN_RUN);
552 /* We need a union to cast dlsym return value to a function pointer
553 as ISO C forbids assignment between function pointer and 'void *'.
554 Use explicit union instead of __extension__(<union_cast>) for
556 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
557 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
558 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
560 /* Try to initialize PLUGIN. Return true if successful. */
563 try_init_one_plugin (struct plugin_name_args *plugin)
566 plugin_init_func plugin_init;
568 PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
570 dl_handle = dlopen (plugin->full_name, RTLD_NOW);
573 error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
577 /* Clear any existing error. */
580 PTR_UNION_AS_VOID_PTR (plugin_init_union) =
581 dlsym (dl_handle, str_plugin_init_func_name);
582 plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
584 if ((err = dlerror ()) != NULL)
586 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
587 plugin->full_name, err);
591 /* Call the plugin-provided initialization routine with the arguments. */
592 if ((*plugin_init) (plugin->base_name, plugin->argc, plugin->argv))
594 error ("Fail to initialize plugin %s", plugin->full_name);
602 /* Routine to dlopen and initialize one plugin. This function is passed to
603 (and called by) the hash table traverse routine. Return 1 for the
604 htab_traverse to continue scan, 0 to stop.
606 SLOT - slot of the hash table element
607 INFO - auxiliary pointer handed to hash table traverse routine
608 (unused in this function) */
611 init_one_plugin (void **slot, void * ARG_UNUSED (info))
613 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
614 bool ok = try_init_one_plugin (plugin);
617 htab_remove_elt (plugin_name_args_tab, plugin->base_name);
623 #endif /* ENABLE_PLUGIN */
625 /* Main plugin initialization function. Called from compile_file() in
629 initialize_plugins (void)
631 /* If no plugin was specified in the command-line, simply return. */
632 if (!plugin_name_args_tab)
635 timevar_push (TV_PLUGIN_INIT);
638 /* Traverse and initialize each plugin specified in the command-line. */
639 htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
642 timevar_pop (TV_PLUGIN_INIT);
645 /* Release memory used by one plugin. */
648 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
650 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
655 /* Free memory allocated by the plugin system. */
658 finalize_plugins (void)
660 if (!plugin_name_args_tab)
663 /* We can now delete the plugin_name_args object as it will no longer
664 be used. Note that base_name and argv fields (both of which were also
665 dynamically allocated) are not freed as they could still be used by
668 htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
670 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
671 htab_delete (plugin_name_args_tab);
672 plugin_name_args_tab = NULL;
675 /* Used to pass options to htab_traverse callbacks. */
683 /* Print the version of one plugin. */
686 print_version_one_plugin (void **slot, void *data)
688 struct print_options *opt = (struct print_options *) data;
689 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
690 const char *version = plugin->version ? plugin->version : "Unknown version.";
692 fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
696 /* Print the version of each plugin. */
699 print_plugins_versions (FILE *file, const char *indent)
701 struct print_options opt;
704 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
707 fprintf (file, "%sVersions of loaded plugins:\n", indent);
708 htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
712 /* Return true if plugins have been loaded. */
715 plugins_active_p (void)
717 enum plugin_event event;
719 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
720 if (plugin_callbacks[event])
727 /* Dump to FILE the names and associated events for all the active
731 dump_active_plugins (FILE *file)
733 enum plugin_event event;
735 if (!plugins_active_p ())
738 fprintf (stderr, "Event\t\t\tPlugins\n");
739 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
740 if (plugin_callbacks[event])
742 struct callback_info *ci;
744 fprintf (file, "%s\t", plugin_event_name[event]);
746 for (ci = plugin_callbacks[event]; ci; ci = ci->next)
747 fprintf (file, "%s ", ci->plugin_name);
749 fprintf (file, "\n");
754 /* Dump active plugins to stderr. */
757 debug_active_plugins (void)
759 dump_active_plugins (stderr);