bitmap.h (bitmap_ior_and_into): New.
[official-gcc.git] / gcc / plugin.c
blob396850a3a970150f268a333a6b460d6bb2911063
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)
9 any later version.
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. */
23 #include "config.h"
24 #include "system.h"
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 too many conditional compilation paths in the rest
29 of the compiler. */
30 #ifdef ENABLE_PLUGIN
31 #include <dlfcn.h>
32 #endif
34 #include "coretypes.h"
35 #include "toplev.h"
36 #include "tree.h"
37 #include "tree-pass.h"
38 #include "intl.h"
39 #include "plugin.h"
40 #include "timevar.h"
41 #include "ggc.h"
43 #ifdef ENABLE_PLUGIN
44 #include "plugin-version.h"
45 #endif
47 /* Event names as strings. Keep in sync with enum plugin_event. */
48 const char *plugin_event_name[] =
50 "PLUGIN_PASS_MANAGER_SETUP",
51 "PLUGIN_FINISH_TYPE",
52 "PLUGIN_FINISH_UNIT",
53 "PLUGIN_CXX_CP_PRE_GENERICIZE",
54 "PLUGIN_FINISH",
55 "PLUGIN_INFO",
56 "PLUGIN_GGC_START",
57 "PLUGIN_GGC_MARKING",
58 "PLUGIN_GGC_END",
59 "PLUGIN_REGISTER_GGC_ROOTS",
60 "PLUGIN_EVENT_LAST"
63 /* Hash table for the plugin_name_args objects created during command-line
64 parsing. */
65 static htab_t plugin_name_args_tab = NULL;
67 /* List node for keeping track of plugin-registered callback. */
68 struct callback_info
70 const char *plugin_name; /* Name of plugin that registers the callback. */
71 plugin_callback_func func; /* Callback to be called. */
72 void *user_data; /* plugin-specified data. */
73 struct callback_info *next;
76 /* An array of lists of 'callback_info' objects indexed by the event id. */
77 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
79 /* List node for an inserted pass instance. We need to keep track of all
80 the newly-added pass instances (with 'added_pass_nodes' defined below)
81 so that we can register their dump files after pass-positioning is finished.
82 Registering dumping files needs to be post-processed or the
83 static_pass_number of the opt_pass object would be modified and mess up
84 the dump file names of future pass instances to be added. */
85 struct pass_list_node
87 struct opt_pass *pass;
88 struct pass_list_node *next;
91 static struct pass_list_node *added_pass_nodes = NULL;
92 static struct pass_list_node *prev_added_pass_node;
94 #ifdef ENABLE_PLUGIN
95 /* Each plugin should define an initialization function with exactly
96 this name. */
97 static const char *str_plugin_init_func_name = "plugin_init";
99 /* Each plugin should define this symbol to assert that it is
100 distributed under a GPL-compatible license. */
101 static const char *str_license = "plugin_is_GPL_compatible";
102 #endif
104 /* Helper function for the hash table that compares the base_name of the
105 existing entry (S1) with the given string (S2). */
107 static int
108 htab_str_eq (const void *s1, const void *s2)
110 const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
111 return !strcmp (plugin->base_name, (const char *) s2);
115 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
116 return NAME. */
118 static char *
119 get_plugin_base_name (const char *full_name)
121 /* First get the base name part of the full-path name, i.e. NAME.so. */
122 char *base_name = xstrdup (lbasename (full_name));
124 /* Then get rid of '.so' part of the name. */
125 strip_off_ending (base_name, strlen (base_name));
127 return base_name;
131 /* Create a plugin_name_args object for the give plugin and insert it to
132 the hash table. This function is called when -fplugin=/path/to/NAME.so
133 option is processed. */
135 void
136 add_new_plugin (const char* plugin_name)
138 struct plugin_name_args *plugin;
139 void **slot;
140 char *base_name = get_plugin_base_name (plugin_name);
142 /* If this is the first -fplugin= option we encounter, create
143 'plugin_name_args_tab' hash table. */
144 if (!plugin_name_args_tab)
145 plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
146 NULL);
148 slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
150 /* If the same plugin (name) has been specified earlier, either emit an
151 error or a warning message depending on if they have identical full
152 (path) names. */
153 if (*slot)
155 plugin = (struct plugin_name_args *) *slot;
156 if (strcmp (plugin->full_name, plugin_name))
157 error ("Plugin %s was specified with different paths:\n%s\n%s",
158 plugin->base_name, plugin->full_name, plugin_name);
159 return;
162 plugin = XCNEW (struct plugin_name_args);
163 plugin->base_name = base_name;
164 plugin->full_name = plugin_name;
166 *slot = plugin;
170 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
171 'plugin_argument' object for the parsed key-value pair. ARG is
172 the <name>-<key>[=<value>] part of the option. */
174 void
175 parse_plugin_arg_opt (const char *arg)
177 size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
178 const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
179 char *name, *key, *value;
180 void **slot;
181 bool name_parsed = false, key_parsed = false;
183 /* Iterate over the ARG string and identify the starting character position
184 of 'name', 'key', and 'value' and their lengths. */
185 for (ptr = arg; *ptr; ++ptr)
187 /* Only the first '-' encountered is considered a separator between
188 'name' and 'key'. All the subsequent '-'s are considered part of
189 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
190 the plugin name is 'foo' and the key is 'bar-primary-key'. */
191 if (*ptr == '-' && !name_parsed)
193 name_len = len;
194 len = 0;
195 key_start = ptr + 1;
196 name_parsed = true;
197 continue;
199 else if (*ptr == '=')
201 if (key_parsed)
203 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
204 arg);
205 return;
207 key_len = len;
208 len = 0;
209 value_start = ptr + 1;
210 key_parsed = true;
211 continue;
213 else
214 ++len;
217 if (!key_start)
219 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
220 arg);
221 return;
224 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
225 Otherwise, it is the VALUE_LEN. */
226 if (!value_start)
227 key_len = len;
228 else
229 value_len = len;
231 name = XNEWVEC (char, name_len + 1);
232 strncpy (name, name_start, name_len);
233 name[name_len] = '\0';
235 /* Check if the named plugin has already been specified earlier in the
236 command-line. */
237 if (plugin_name_args_tab
238 && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
239 != NULL))
241 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
243 key = XNEWVEC (char, key_len + 1);
244 strncpy (key, key_start, key_len);
245 key[key_len] = '\0';
246 if (value_start)
248 value = XNEWVEC (char, value_len + 1);
249 strncpy (value, value_start, value_len);
250 value[value_len] = '\0';
252 else
253 value = NULL;
255 /* Create a plugin_argument object for the parsed key-value pair.
256 If there are already arguments for this plugin, we will need to
257 adjust the argument array size by creating a new array and deleting
258 the old one. If the performance ever becomes an issue, we can
259 change the code by pre-allocating a larger array first. */
260 if (plugin->argc > 0)
262 struct plugin_argument *args = XNEWVEC (struct plugin_argument,
263 plugin->argc + 1);
264 memcpy (args, plugin->argv,
265 sizeof (struct plugin_argument) * plugin->argc);
266 XDELETEVEC (plugin->argv);
267 plugin->argv = args;
268 ++plugin->argc;
270 else
272 gcc_assert (plugin->argv == NULL);
273 plugin->argv = XNEWVEC (struct plugin_argument, 1);
274 plugin->argc = 1;
277 plugin->argv[plugin->argc - 1].key = key;
278 plugin->argv[plugin->argc - 1].value = value;
280 else
281 error ("Plugin %s should be specified before -fplugin-arg-%s "
282 "in the command line", name, arg);
284 /* We don't need the plugin's name anymore. Just release it. */
285 XDELETEVEC (name);
289 /* Insert the plugin pass at the proper position. Return true if the pass
290 is successfully added.
292 PLUGIN_PASS_INFO - new pass to be inserted
293 PASS_LIST - root of the pass list to insert the new pass to */
295 static bool
296 position_pass (struct plugin_pass *plugin_pass_info,
297 struct opt_pass **pass_list)
299 struct opt_pass *pass = *pass_list, *prev_pass = NULL;
300 bool success = false;
302 for ( ; pass; prev_pass = pass, pass = pass->next)
304 /* Check if the current pass is of the same type as the new pass and
305 matches the name and the instance number of the reference pass. */
306 if (pass->type == plugin_pass_info->pass->type
307 && pass->name
308 && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
309 && ((plugin_pass_info->ref_pass_instance_number == 0)
310 || (plugin_pass_info->ref_pass_instance_number ==
311 pass->static_pass_number)
312 || (plugin_pass_info->ref_pass_instance_number == 1
313 && pass->todo_flags_start & TODO_mark_first_instance)))
315 struct opt_pass *new_pass = plugin_pass_info->pass;
316 struct pass_list_node *new_pass_node;
318 /* The following code (if-statement) is adopted from next_pass_1. */
319 if (new_pass->static_pass_number)
321 new_pass = XNEW (struct opt_pass);
322 memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
323 new_pass->next = NULL;
325 new_pass->todo_flags_start &= ~TODO_mark_first_instance;
327 plugin_pass_info->pass->static_pass_number -= 1;
328 new_pass->static_pass_number =
329 -plugin_pass_info->pass->static_pass_number;
331 else
333 new_pass->todo_flags_start |= TODO_mark_first_instance;
334 new_pass->static_pass_number = -1;
337 /* Insert the new pass instance based on the positioning op. */
338 switch (plugin_pass_info->pos_op)
340 case PASS_POS_INSERT_AFTER:
341 new_pass->next = pass->next;
342 pass->next = new_pass;
344 /* Skip newly inserted pass to avoid repeated
345 insertions in the case where the new pass and the
346 existing one have the same name. */
347 pass = new_pass;
348 break;
349 case PASS_POS_INSERT_BEFORE:
350 new_pass->next = pass;
351 if (prev_pass)
352 prev_pass->next = new_pass;
353 else
354 *pass_list = new_pass;
355 break;
356 case PASS_POS_REPLACE:
357 new_pass->next = pass->next;
358 if (prev_pass)
359 prev_pass->next = new_pass;
360 else
361 *pass_list = new_pass;
362 new_pass->sub = pass->sub;
363 new_pass->tv_id = pass->tv_id;
364 pass = new_pass;
365 break;
366 default:
367 error ("Invalid pass positioning operation");
368 return false;
371 /* Save the newly added pass (instance) in the added_pass_nodes
372 list so that we can register its dump file later. Note that
373 we cannot register the dump file now because doing so will modify
374 the static_pass_number of the opt_pass object and therefore
375 mess up the dump file name of future instances. */
376 new_pass_node = XCNEW (struct pass_list_node);
377 new_pass_node->pass = new_pass;
378 if (!added_pass_nodes)
379 added_pass_nodes = new_pass_node;
380 else
381 prev_added_pass_node->next = new_pass_node;
382 prev_added_pass_node = new_pass_node;
384 success = true;
387 if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
388 success = true;
391 return success;
395 /* Hook into the pass lists (trees) a new pass registered by a plugin.
397 PLUGIN_NAME - display name for the plugin
398 PASS_INFO - plugin pass information that specifies the opt_pass object,
399 reference pass, instance number, and how to position
400 the pass */
402 static void
403 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
405 if (!pass_info->pass)
407 error ("No pass specified when registering a new pass in plugin %s",
408 plugin_name);
409 return;
412 if (!pass_info->reference_pass_name)
414 error ("No reference pass specified for positioning the pass "
415 " from plugin %s", plugin_name);
416 return;
419 /* Try to insert the new pass to the pass lists. We need to check all
420 three lists as the reference pass could be in one (or all) of them. */
421 if (!position_pass (pass_info, &all_lowering_passes)
422 && !position_pass (pass_info, &all_ipa_passes)
423 && !position_pass (pass_info, &all_passes))
424 error ("Failed to position pass %s registered by plugin %s. "
425 "Cannot find the (specified instance of) reference pass %s",
426 pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
427 else
429 /* OK, we have successfully inserted the new pass. We need to register
430 the dump files for the newly added pass and its duplicates (if any).
431 Because the registration of plugin passes happens after the
432 command-line options are parsed, the options that specify single
433 pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
434 plugin passes. Therefore we currently can only enable dumping of
435 new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
436 are specified. While doing so, we also delete the pass_list_node
437 objects created during pass positioning. */
438 while (added_pass_nodes)
440 struct pass_list_node *next_node = added_pass_nodes->next;
441 enum tree_dump_index tdi;
442 register_one_dump_file (added_pass_nodes->pass);
443 if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
444 || added_pass_nodes->pass->type == IPA_PASS)
445 tdi = TDI_ipa_all;
446 else if (added_pass_nodes->pass->type == GIMPLE_PASS)
447 tdi = TDI_tree_all;
448 else
449 tdi = TDI_rtl_all;
450 /* Check if dump-all flag is specified. */
451 if (get_dump_file_info (tdi)->state)
452 get_dump_file_info (added_pass_nodes->pass->static_pass_number)
453 ->state = get_dump_file_info (tdi)->state;
454 XDELETE (added_pass_nodes);
455 added_pass_nodes = next_node;
461 /* Register additional plugin information. NAME is the name passed to
462 plugin_init. INFO is the information that should be registered. */
464 static void
465 register_plugin_info (const char* name, struct plugin_info *info)
467 void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
468 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
469 plugin->version = info->version;
470 plugin->help = info->help;
473 /* Called from the plugin's initialization code. Register a single callback.
474 This function can be called multiple times.
476 PLUGIN_NAME - display name for this plugin
477 EVENT - which event the callback is for
478 CALLBACK - the callback to be called at the event
479 USER_DATA - plugin-provided data */
481 void
482 register_callback (const char *plugin_name,
483 enum plugin_event event,
484 plugin_callback_func callback,
485 void *user_data)
487 switch (event)
489 case PLUGIN_PASS_MANAGER_SETUP:
490 gcc_assert (!callback);
491 register_pass (plugin_name, (struct plugin_pass *) user_data);
492 break;
493 case PLUGIN_INFO:
494 gcc_assert (!callback);
495 register_plugin_info (plugin_name, (struct plugin_info *) user_data);
496 break;
497 case PLUGIN_REGISTER_GGC_ROOTS:
498 gcc_assert (!callback);
499 ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
500 break;
501 case PLUGIN_FINISH_TYPE:
502 case PLUGIN_FINISH_UNIT:
503 case PLUGIN_CXX_CP_PRE_GENERICIZE:
504 case PLUGIN_GGC_START:
505 case PLUGIN_GGC_MARKING:
506 case PLUGIN_GGC_END:
507 case PLUGIN_ATTRIBUTES:
508 case PLUGIN_FINISH:
510 struct callback_info *new_callback;
511 if (!callback)
513 error ("Plugin %s registered a null callback function "
514 "for event %s", plugin_name, plugin_event_name[event]);
515 return;
517 new_callback = XNEW (struct callback_info);
518 new_callback->plugin_name = plugin_name;
519 new_callback->func = callback;
520 new_callback->user_data = user_data;
521 new_callback->next = plugin_callbacks[event];
522 plugin_callbacks[event] = new_callback;
524 break;
525 case PLUGIN_EVENT_LAST:
526 default:
527 error ("Unkown callback event registered by plugin %s",
528 plugin_name);
533 /* Called from inside GCC. Invoke all plug-in callbacks registered with
534 the specified event.
536 EVENT - the event identifier
537 GCC_DATA - event-specific data provided by the compiler */
539 void
540 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
542 timevar_push (TV_PLUGIN_RUN);
544 switch (event)
546 case PLUGIN_FINISH_TYPE:
547 case PLUGIN_FINISH_UNIT:
548 case PLUGIN_CXX_CP_PRE_GENERICIZE:
549 case PLUGIN_ATTRIBUTES:
550 case PLUGIN_FINISH:
551 case PLUGIN_GGC_START:
552 case PLUGIN_GGC_MARKING:
553 case PLUGIN_GGC_END:
555 /* Iterate over every callback registered with this event and
556 call it. */
557 struct callback_info *callback = plugin_callbacks[event];
558 for ( ; callback; callback = callback->next)
559 (*callback->func) (gcc_data, callback->user_data);
561 break;
563 case PLUGIN_PASS_MANAGER_SETUP:
564 case PLUGIN_EVENT_LAST:
565 case PLUGIN_REGISTER_GGC_ROOTS:
566 default:
567 gcc_assert (false);
570 timevar_pop (TV_PLUGIN_RUN);
573 #ifdef ENABLE_PLUGIN
574 /* We need a union to cast dlsym return value to a function pointer
575 as ISO C forbids assignment between function pointer and 'void *'.
576 Use explicit union instead of __extension__(<union_cast>) for
577 portability. */
578 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
579 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
580 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
582 /* Try to initialize PLUGIN. Return true if successful. */
584 static bool
585 try_init_one_plugin (struct plugin_name_args *plugin)
587 void *dl_handle;
588 plugin_init_func plugin_init;
589 char *err;
590 PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
592 dl_handle = dlopen (plugin->full_name, RTLD_NOW);
593 if (!dl_handle)
595 error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
596 return false;
599 /* Clear any existing error. */
600 dlerror ();
602 /* Check the plugin license. */
603 if (dlsym (dl_handle, str_license) == NULL)
604 fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
605 "%s", plugin->full_name, dlerror ());
607 PTR_UNION_AS_VOID_PTR (plugin_init_union) =
608 dlsym (dl_handle, str_plugin_init_func_name);
609 plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
611 if ((err = dlerror ()) != NULL)
613 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
614 plugin->full_name, err);
615 return false;
618 /* Call the plugin-provided initialization routine with the arguments. */
619 if ((*plugin_init) (plugin, &gcc_version))
621 error ("Fail to initialize plugin %s", plugin->full_name);
622 return false;
625 return true;
629 /* Routine to dlopen and initialize one plugin. This function is passed to
630 (and called by) the hash table traverse routine. Return 1 for the
631 htab_traverse to continue scan, 0 to stop.
633 SLOT - slot of the hash table element
634 INFO - auxiliary pointer handed to hash table traverse routine
635 (unused in this function) */
637 static int
638 init_one_plugin (void **slot, void * ARG_UNUSED (info))
640 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
641 bool ok = try_init_one_plugin (plugin);
642 if (!ok)
644 htab_remove_elt (plugin_name_args_tab, plugin->base_name);
645 XDELETE (plugin);
647 return 1;
650 #endif /* ENABLE_PLUGIN */
652 /* Main plugin initialization function. Called from compile_file() in
653 toplev.c. */
655 void
656 initialize_plugins (void)
658 /* If no plugin was specified in the command-line, simply return. */
659 if (!plugin_name_args_tab)
660 return;
662 timevar_push (TV_PLUGIN_INIT);
664 #ifdef ENABLE_PLUGIN
665 /* Traverse and initialize each plugin specified in the command-line. */
666 htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
667 #endif
669 timevar_pop (TV_PLUGIN_INIT);
672 /* Release memory used by one plugin. */
674 static int
675 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
677 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
678 XDELETE (plugin);
679 return 1;
682 /* Free memory allocated by the plugin system. */
684 void
685 finalize_plugins (void)
687 if (!plugin_name_args_tab)
688 return;
690 /* We can now delete the plugin_name_args object as it will no longer
691 be used. Note that base_name and argv fields (both of which were also
692 dynamically allocated) are not freed as they could still be used by
693 the plugin code. */
695 htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
697 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
698 htab_delete (plugin_name_args_tab);
699 plugin_name_args_tab = NULL;
702 /* Used to pass options to htab_traverse callbacks. */
704 struct print_options
706 FILE *file;
707 const char *indent;
710 /* Print the version of one plugin. */
712 static int
713 print_version_one_plugin (void **slot, void *data)
715 struct print_options *opt = (struct print_options *) data;
716 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
717 const char *version = plugin->version ? plugin->version : "Unknown version.";
719 fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
720 return 1;
723 /* Print the version of each plugin. */
725 void
726 print_plugins_versions (FILE *file, const char *indent)
728 struct print_options opt;
729 opt.file = file;
730 opt.indent = indent;
731 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
732 return;
734 fprintf (file, "%sVersions of loaded plugins:\n", indent);
735 htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
738 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
739 argument to htab_traverse_noresize. */
741 static int
742 print_help_one_plugin (void **slot, void *data)
744 struct print_options *opt = (struct print_options *) data;
745 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
746 const char *help = plugin->help ? plugin->help : "No help available .";
748 char *dup = xstrdup (help);
749 char *p, *nl;
750 fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
752 for (p = nl = dup; nl; p = nl)
754 nl = strchr (nl, '\n');
755 if (nl)
757 *nl = '\0';
758 nl++;
760 fprintf (opt->file, " %s %s\n", opt->indent, p);
763 free (dup);
764 return 1;
767 /* Print help for each plugin. The output goes to FILE and every line starts
768 with INDENT. */
770 void
771 print_plugins_help (FILE *file, const char *indent)
773 struct print_options opt;
774 opt.file = file;
775 opt.indent = indent;
776 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
777 return;
779 fprintf (file, "%sHelp for the loaded plugins:\n", indent);
780 htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
784 /* Return true if plugins have been loaded. */
786 bool
787 plugins_active_p (void)
789 int event;
791 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
792 if (plugin_callbacks[event])
793 return true;
795 return false;
799 /* Dump to FILE the names and associated events for all the active
800 plugins. */
802 void
803 dump_active_plugins (FILE *file)
805 int event;
807 if (!plugins_active_p ())
808 return;
810 fprintf (stderr, "Event\t\t\tPlugins\n");
811 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
812 if (plugin_callbacks[event])
814 struct callback_info *ci;
816 fprintf (file, "%s\t", plugin_event_name[event]);
818 for (ci = plugin_callbacks[event]; ci; ci = ci->next)
819 fprintf (file, "%s ", ci->plugin_name);
821 fprintf (file, "\n");
826 /* Dump active plugins to stderr. */
828 void
829 debug_active_plugins (void)
831 dump_active_plugins (stderr);
834 /* The default version check. Compares every field in VERSION. */
836 bool
837 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
838 struct plugin_gcc_version *plugin_version)
840 if (!gcc_version || !plugin_version)
841 return false;
843 if (strcmp (gcc_version->basever, plugin_version->basever))
844 return false;
845 if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
846 return false;
847 if (strcmp (gcc_version->devphase, plugin_version->devphase))
848 return false;
849 if (strcmp (gcc_version->revision, plugin_version->revision))
850 return false;
851 if (strcmp (gcc_version->configuration_arguments,
852 plugin_version->configuration_arguments))
853 return false;
854 return true;