OSDN Git Service

* cgraph.c (dump_cgraph_node): Dump size/time/benefit.
[pf3gnuchains/gcc-fork.git] / gcc / plugin.c
1 /* Support for GCC plugin mechanism.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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.
10
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.
15
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/>.  */
19
20 /* This file contains the support for GCC plugin mechanism based on the
21    APIs described in doc/plugin.texi.  */
22
23 #include "config.h"
24 #include "system.h"
25
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
29    of the compiler.  */
30 #ifdef ENABLE_PLUGIN
31 #include <dlfcn.h>
32 #endif
33
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 #ifdef ENABLE_PLUGIN
42 #include "plugin-version.h"
43 #endif
44
45 /* Event names as strings.  Keep in sync with enum plugin_event.  */
46 const char *plugin_event_name[] =
47 {
48   "PLUGIN_PASS_MANAGER_SETUP",
49   "PLUGIN_FINISH_TYPE",
50   "PLUGIN_FINISH_UNIT",
51   "PLUGIN_CXX_CP_PRE_GENERICIZE",
52   "PLUGIN_FINISH",
53   "PLUGIN_INFO",
54   "PLUGIN_EVENT_LAST"
55 };
56
57 /* Hash table for the plugin_name_args objects created during command-line
58    parsing.  */
59 static htab_t plugin_name_args_tab = NULL;
60
61 /* List node for keeping track of plugin-registered callback.  */
62 struct callback_info
63 {
64   const char *plugin_name;   /* Name of plugin that registers the callback.  */
65   plugin_callback_func func; /* Callback to be called.  */
66   void *user_data;           /* plugin-specified data.  */
67   struct callback_info *next;
68 };
69
70 /* An array of lists of 'callback_info' objects indexed by the event id.  */
71 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
72
73 /* List node for an inserted pass instance. We need to keep track of all
74    the newly-added pass instances (with 'added_pass_nodes' defined below)
75    so that we can register their dump files after pass-positioning is finished.
76    Registering dumping files needs to be post-processed or the
77    static_pass_number of the opt_pass object would be modified and mess up
78    the dump file names of future pass instances to be added.  */
79 struct pass_list_node
80 {
81   struct opt_pass *pass;
82   struct pass_list_node *next;
83 };
84
85 static struct pass_list_node *added_pass_nodes = NULL;
86 static struct pass_list_node *prev_added_pass_node;
87
88 #ifdef ENABLE_PLUGIN
89 /* Each plugin should define an initialization function with exactly
90    this name.  */
91 static const char *str_plugin_init_func_name = "plugin_init";
92 #endif
93
94 /* Helper function for the hash table that compares the base_name of the
95    existing entry (S1) with the given string (S2).  */
96
97 static int
98 htab_str_eq (const void *s1, const void *s2)
99 {
100   const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
101   return !strcmp (plugin->base_name, (const char *) s2);
102 }
103
104
105 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
106    return NAME.  */
107
108 static char *
109 get_plugin_base_name (const char *full_name)
110 {
111   /* First get the base name part of the full-path name, i.e. NAME.so.  */
112   char *base_name = xstrdup (lbasename (full_name));
113
114   /* Then get rid of '.so' part of the name.  */
115   strip_off_ending (base_name, strlen (base_name));
116
117   return base_name;
118 }
119
120
121 /* Create a plugin_name_args object for the give plugin and insert it to
122    the hash table. This function is called when -fplugin=/path/to/NAME.so
123    option is processed.  */
124
125 void
126 add_new_plugin (const char* plugin_name)
127 {
128   struct plugin_name_args *plugin;
129   void **slot;
130   char *base_name = get_plugin_base_name (plugin_name);
131
132   /* If this is the first -fplugin= option we encounter, create 
133      'plugin_name_args_tab' hash table.  */
134   if (!plugin_name_args_tab)
135     plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
136                                         NULL);
137
138   slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
139
140   /* If the same plugin (name) has been specified earlier, either emit an
141      error or a warning message depending on if they have identical full
142      (path) names.  */
143   if (*slot)
144     {
145       plugin = (struct plugin_name_args *) *slot;
146       if (strcmp (plugin->full_name, plugin_name))
147         error ("Plugin %s was specified with different paths:\n%s\n%s",
148                plugin->base_name, plugin->full_name, plugin_name);
149       return;
150     }
151
152   plugin = XCNEW (struct plugin_name_args);
153   plugin->base_name = base_name;
154   plugin->full_name = plugin_name;
155
156   *slot = plugin;
157 }
158
159
160 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
161    'plugin_argument' object for the parsed key-value pair. ARG is
162    the <name>-<key>[=<value>] part of the option.  */
163
164 void
165 parse_plugin_arg_opt (const char *arg)
166 {
167   size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
168   const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
169   char *name, *key, *value;
170   void **slot;
171   bool name_parsed = false, key_parsed = false;
172
173   /* Iterate over the ARG string and identify the starting character position
174      of 'name', 'key', and 'value' and their lengths.  */
175   for (ptr = arg; *ptr; ++ptr)
176     {
177       /* Only the first '-' encountered is considered a separator between
178          'name' and 'key'. All the subsequent '-'s are considered part of
179          'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
180          the plugin name is 'foo' and the key is 'bar-primary-key'.  */
181       if (*ptr == '-' && !name_parsed)
182         {
183           name_len = len;
184           len = 0;
185           key_start = ptr + 1;
186           name_parsed = true;
187           continue;
188         }
189       else if (*ptr == '=')
190         {
191           if (key_parsed)
192             {
193               error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
194                      arg);
195               return;
196             }
197           key_len = len;
198           len = 0;
199           value_start = ptr + 1;
200           key_parsed = true;
201           continue;
202         }
203       else
204         ++len;
205     }
206
207   if (!key_start)
208     {
209       error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
210              arg);
211       return;
212     }
213
214   /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
215      Otherwise, it is the VALUE_LEN.  */
216   if (!value_start)
217     key_len = len;
218   else
219     value_len = len;
220
221   name = XNEWVEC (char, name_len + 1);
222   strncpy (name, name_start, name_len);
223   name[name_len] = '\0';
224
225   /* Check if the named plugin has already been specified earlier in the
226      command-line.  */
227   if (plugin_name_args_tab
228       && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
229           != NULL))
230     {
231       struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
232
233       key = XNEWVEC (char, key_len + 1);
234       strncpy (key, key_start, key_len);
235       key[key_len] = '\0';
236       if (value_start)
237         {
238           value = XNEWVEC (char, value_len + 1);
239           strncpy (value, value_start, value_len);
240           value[value_len] = '\0';
241         }
242       else
243         value = NULL;
244
245       /* Create a plugin_argument object for the parsed key-value pair.
246          If there are already arguments for this plugin, we will need to
247          adjust the argument array size by creating a new array and deleting
248          the old one. If the performance ever becomes an issue, we can
249          change the code by pre-allocating a larger array first.  */
250       if (plugin->argc > 0)
251         {
252           struct plugin_argument *args = XNEWVEC (struct plugin_argument,
253                                                   plugin->argc + 1);
254           memcpy (args, plugin->argv,
255                   sizeof (struct plugin_argument) * plugin->argc);
256           XDELETEVEC (plugin->argv);
257           plugin->argv = args;
258           ++plugin->argc;
259         }
260       else
261         {
262           gcc_assert (plugin->argv == NULL);
263           plugin->argv = XNEWVEC (struct plugin_argument, 1);
264           plugin->argc = 1;
265         }
266
267       plugin->argv[plugin->argc - 1].key = key;
268       plugin->argv[plugin->argc - 1].value = value;
269     }
270   else
271     error ("Plugin %s should be specified before -fplugin-arg-%s "
272            "in the command line", name, arg);
273
274   /* We don't need the plugin's name anymore. Just release it.  */
275   XDELETEVEC (name);
276 }
277
278
279 /* Insert the plugin pass at the proper position. Return true if the pass 
280    is successfully added.
281
282    PLUGIN_PASS_INFO - new pass to be inserted
283    PASS_LIST        - root of the pass list to insert the new pass to  */
284
285 static bool
286 position_pass (struct plugin_pass *plugin_pass_info,
287                struct opt_pass **pass_list)
288 {
289   struct opt_pass *pass = *pass_list, *prev_pass = NULL;
290   bool success = false;
291
292   for ( ; pass; prev_pass = pass, pass = pass->next)
293     {
294       /* Check if the current pass is of the same type as the new pass and
295          matches the name and the instance number of the reference pass.  */
296       if (pass->type == plugin_pass_info->pass->type
297           && pass->name
298           && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
299           && ((plugin_pass_info->ref_pass_instance_number == 0)
300               || (plugin_pass_info->ref_pass_instance_number ==
301                   pass->static_pass_number)
302               || (plugin_pass_info->ref_pass_instance_number == 1
303                   && pass->todo_flags_start & TODO_mark_first_instance)))
304         {
305           struct opt_pass *new_pass = plugin_pass_info->pass;
306           struct pass_list_node *new_pass_node;
307
308           /* The following code (if-statement) is adopted from next_pass_1.  */
309           if (new_pass->static_pass_number)
310             {
311               new_pass = XNEW (struct opt_pass);
312               memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
313               new_pass->next = NULL;
314
315               new_pass->todo_flags_start &= ~TODO_mark_first_instance;
316
317               plugin_pass_info->pass->static_pass_number -= 1;
318               new_pass->static_pass_number =
319                   -plugin_pass_info->pass->static_pass_number;
320             }
321           else
322             {
323               new_pass->todo_flags_start |= TODO_mark_first_instance;
324               new_pass->static_pass_number = -1;
325             }
326
327           /* Insert the new pass instance based on the positioning op.  */
328           switch (plugin_pass_info->pos_op)
329             {
330               case PASS_POS_INSERT_AFTER:
331                 new_pass->next = pass->next;
332                 pass->next = new_pass;
333                 break;
334               case PASS_POS_INSERT_BEFORE:
335                 new_pass->next = pass;
336                 if (prev_pass)
337                   prev_pass->next = new_pass;
338                 else
339                   *pass_list = new_pass;
340                 break;
341               case PASS_POS_REPLACE:
342                 new_pass->next = pass->next;
343                 if (prev_pass)
344                   prev_pass->next = new_pass;
345                 else
346                   *pass_list = new_pass;
347                 new_pass->sub = pass->sub;
348                 new_pass->tv_id = pass->tv_id;
349                 pass = new_pass;
350                 break;
351               default:
352                 error ("Invalid pass positioning operation");
353                 return false;
354             }
355
356           /* Save the newly added pass (instance) in the added_pass_nodes
357              list so that we can register its dump file later. Note that
358              we cannot register the dump file now because doing so will modify
359              the static_pass_number of the opt_pass object and therefore
360              mess up the dump file name of future instances.  */
361           new_pass_node = XCNEW (struct pass_list_node);
362           new_pass_node->pass = new_pass;
363           if (!added_pass_nodes)
364             added_pass_nodes = new_pass_node;
365           else
366             prev_added_pass_node->next = new_pass_node;
367           prev_added_pass_node = new_pass_node;
368
369           success = true;
370         }
371
372       if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
373         success = true;
374     }
375
376   return success;
377 }
378
379
380 /* Hook into the pass lists (trees) a new pass registered by a plugin.
381
382    PLUGIN_NAME - display name for the plugin
383    PASS_INFO   - plugin pass information that specifies the opt_pass object,
384                  reference pass, instance number, and how to position
385                  the pass  */
386
387 static void
388 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
389 {
390   if (!pass_info->pass)
391     {
392       error ("No pass specified when registering a new pass in plugin %s",
393              plugin_name);
394       return;
395     }
396
397   if (!pass_info->reference_pass_name)
398     {
399       error ("No reference pass specified for positioning the pass "
400              " from plugin %s", plugin_name);
401       return;
402     }
403
404   /* Try to insert the new pass to the pass lists. We need to check all
405      three lists as the reference pass could be in one (or all) of them.  */
406   if (!position_pass (pass_info, &all_lowering_passes)
407       && !position_pass (pass_info, &all_ipa_passes)
408       && !position_pass (pass_info, &all_passes))
409     error ("Failed to position pass %s registered by plugin %s. "
410            "Cannot find the (specified instance of) reference pass %s",
411            pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
412   else
413     {
414       /* OK, we have successfully inserted the new pass. We need to register
415          the dump files for the newly added pass and its duplicates (if any).
416          Because the registration of plugin passes happens after the
417          command-line options are parsed, the options that specify single
418          pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
419          plugin passes. Therefore we currently can only enable dumping of
420          new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
421          are specified. While doing so, we also delete the pass_list_node
422          objects created during pass positioning.  */
423       while (added_pass_nodes)
424         {
425           struct pass_list_node *next_node = added_pass_nodes->next;
426           enum tree_dump_index tdi;
427           register_one_dump_file (added_pass_nodes->pass);
428           if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
429               || added_pass_nodes->pass->type == IPA_PASS)
430             tdi = TDI_ipa_all;
431           else if (added_pass_nodes->pass->type == GIMPLE_PASS)
432             tdi = TDI_tree_all;
433           else
434             tdi = TDI_rtl_all;
435           /* Check if dump-all flag is specified.  */
436           if (get_dump_file_info (tdi)->state)
437             get_dump_file_info (added_pass_nodes->pass->static_pass_number)
438                 ->state = get_dump_file_info (tdi)->state;
439           XDELETE (added_pass_nodes);
440           added_pass_nodes = next_node;
441         }
442     }
443 }
444
445
446 /* Register additional plugin information. NAME is the name passed to
447    plugin_init. INFO is the information that should be registered. */
448
449 static void
450 register_plugin_info (const char* name, struct plugin_info *info)
451 {
452   void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
453   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
454   plugin->version = info->version;
455   plugin->help = info->help;
456 }
457
458 /* Called from the plugin's initialization code. Register a single callback.
459    This function can be called multiple times.
460
461    PLUGIN_NAME - display name for this plugin
462    EVENT       - which event the callback is for
463    CALLBACK    - the callback to be called at the event
464    USER_DATA   - plugin-provided data   */
465
466 void
467 register_callback (const char *plugin_name,
468                    enum plugin_event event,
469                    plugin_callback_func callback,
470                    void *user_data)
471 {
472   switch (event)
473     {
474       case PLUGIN_PASS_MANAGER_SETUP:
475         register_pass (plugin_name, (struct plugin_pass *) user_data);
476         break;
477       case PLUGIN_INFO:
478         register_plugin_info (plugin_name, (struct plugin_info *) user_data);
479         break;
480       case PLUGIN_FINISH_TYPE:
481       case PLUGIN_FINISH_UNIT:
482       case PLUGIN_CXX_CP_PRE_GENERICIZE:
483       case PLUGIN_ATTRIBUTES:
484       case PLUGIN_FINISH:
485         {
486           struct callback_info *new_callback;
487           if (!callback)
488             {
489               error ("Plugin %s registered a null callback function "
490                      "for event %s", plugin_name, plugin_event_name[event]);
491               return;
492             }
493           new_callback = XNEW (struct callback_info);
494           new_callback->plugin_name = plugin_name;
495           new_callback->func = callback;
496           new_callback->user_data = user_data;
497           new_callback->next = plugin_callbacks[event];
498           plugin_callbacks[event] = new_callback;
499         }
500         break;
501       case PLUGIN_EVENT_LAST:
502       default:
503         error ("Unkown callback event registered by plugin %s",
504                plugin_name);
505     }
506 }
507
508
509 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
510    the specified event.
511
512    EVENT    - the event identifier
513    GCC_DATA - event-specific data provided by the compiler  */
514
515 void
516 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
517 {
518   timevar_push (TV_PLUGIN_RUN);
519
520   switch (event)
521     {
522       case PLUGIN_FINISH_TYPE:
523       case PLUGIN_FINISH_UNIT:
524       case PLUGIN_CXX_CP_PRE_GENERICIZE:
525       case PLUGIN_ATTRIBUTES:
526       case PLUGIN_FINISH:
527         {
528           /* Iterate over every callback registered with this event and
529              call it.  */
530           struct callback_info *callback = plugin_callbacks[event];
531           for ( ; callback; callback = callback->next)
532             (*callback->func) (gcc_data, callback->user_data);
533         }
534         break;
535
536       case PLUGIN_PASS_MANAGER_SETUP:
537       case PLUGIN_EVENT_LAST:
538       default:
539         gcc_assert (false);
540     }
541
542   timevar_pop (TV_PLUGIN_RUN);
543 }
544
545 #ifdef ENABLE_PLUGIN
546 /* We need a union to cast dlsym return value to a function pointer
547    as ISO C forbids assignment between function pointer and 'void *'.
548    Use explicit union instead of __extension__(<union_cast>) for
549    portability.  */
550 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
551 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
552 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
553
554 /* Try to initialize PLUGIN. Return true if successful. */
555
556 static bool
557 try_init_one_plugin (struct plugin_name_args *plugin)
558 {
559   void *dl_handle;
560   plugin_init_func plugin_init;
561   char *err;
562   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
563
564   dl_handle = dlopen (plugin->full_name, RTLD_NOW);
565   if (!dl_handle)
566     {
567       error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
568       return false;
569     }
570
571   /* Clear any existing error.  */
572   dlerror ();
573
574   PTR_UNION_AS_VOID_PTR (plugin_init_union) =
575       dlsym (dl_handle, str_plugin_init_func_name);
576   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
577
578   if ((err = dlerror ()) != NULL)
579     {
580       error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
581              plugin->full_name, err);
582       return false;
583     }
584
585   /* Call the plugin-provided initialization routine with the arguments.  */
586   if ((*plugin_init) (plugin, &gcc_version))
587     {
588       error ("Fail to initialize plugin %s", plugin->full_name);
589       return false;
590     }
591
592   return true;
593 }
594
595
596 /* Routine to dlopen and initialize one plugin. This function is passed to
597    (and called by) the hash table traverse routine. Return 1 for the
598    htab_traverse to continue scan, 0 to stop.
599
600    SLOT - slot of the hash table element
601    INFO - auxiliary pointer handed to hash table traverse routine
602           (unused in this function)  */
603
604 static int
605 init_one_plugin (void **slot, void * ARG_UNUSED (info))
606 {
607   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
608   bool ok = try_init_one_plugin (plugin);
609   if (!ok)
610     {
611       htab_remove_elt (plugin_name_args_tab, plugin->base_name);
612       XDELETE (plugin);
613     }
614   return 1;
615 }
616
617 #endif  /* ENABLE_PLUGIN  */
618
619 /* Main plugin initialization function.  Called from compile_file() in
620    toplev.c.  */
621
622 void
623 initialize_plugins (void)
624 {
625   /* If no plugin was specified in the command-line, simply return.  */
626   if (!plugin_name_args_tab)
627     return;
628
629   timevar_push (TV_PLUGIN_INIT);
630  
631 #ifdef ENABLE_PLUGIN
632   /* Traverse and initialize each plugin specified in the command-line.  */
633   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
634 #endif
635
636   timevar_pop (TV_PLUGIN_INIT);
637 }
638
639 /* Release memory used by one plugin. */
640
641 static int
642 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
643 {
644   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
645   XDELETE (plugin);
646   return 1;
647 }
648
649 /* Free memory allocated by the plugin system. */
650
651 void
652 finalize_plugins (void)
653 {
654   if (!plugin_name_args_tab)
655     return;
656
657   /* We can now delete the plugin_name_args object as it will no longer
658      be used. Note that base_name and argv fields (both of which were also
659      dynamically allocated) are not freed as they could still be used by
660      the plugin code.  */
661
662   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
663
664   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
665   htab_delete (plugin_name_args_tab);
666   plugin_name_args_tab = NULL;
667 }
668
669 /* Used to pass options to htab_traverse callbacks. */
670
671 struct print_options
672 {
673   FILE *file;
674   const char *indent;
675 };
676
677 /* Print the version of one plugin. */
678
679 static int
680 print_version_one_plugin (void **slot, void *data)
681 {
682   struct print_options *opt = (struct print_options *) data;
683   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
684   const char *version = plugin->version ? plugin->version : "Unknown version.";
685
686   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
687   return 1;
688 }
689
690 /* Print the version of each plugin. */
691
692 void
693 print_plugins_versions (FILE *file, const char *indent)
694 {
695   struct print_options opt;
696   opt.file = file;
697   opt.indent = indent;
698   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
699     return;
700
701   fprintf (file, "%sVersions of loaded plugins:\n", indent);
702   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
703 }
704
705 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
706    argument to htab_traverse_noresize. */
707
708 static int
709 print_help_one_plugin (void **slot, void *data)
710 {
711   struct print_options *opt = (struct print_options *) data;
712   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
713   const char *help = plugin->help ? plugin->help : "No help available .";
714
715   char *dup = xstrdup (help);
716   char *p, *nl;
717   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
718
719   for (p = nl = dup; nl; p = nl)
720     {
721       nl = strchr (nl, '\n');
722       if (nl)
723         {
724           *nl = '\0';
725           nl++;
726         }
727       fprintf (opt->file, "   %s %s\n", opt->indent, p);
728     }
729
730   free (dup);
731   return 1;
732 }
733
734 /* Print help for each plugin. The output goes to FILE and every line starts
735    with INDENT. */
736
737 void
738 print_plugins_help (FILE *file, const char *indent)
739 {
740   struct print_options opt;
741   opt.file = file;
742   opt.indent = indent;
743   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
744     return;
745
746   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
747   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
748 }
749
750
751 /* Return true if plugins have been loaded.  */
752
753 bool
754 plugins_active_p (void)
755 {
756   int event;
757
758   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
759     if (plugin_callbacks[event])
760       return true;
761
762   return false;
763 }
764
765
766 /* Dump to FILE the names and associated events for all the active
767    plugins.  */
768
769 void
770 dump_active_plugins (FILE *file)
771 {
772   int event;
773
774   if (!plugins_active_p ())
775     return;
776
777   fprintf (stderr, "Event\t\t\tPlugins\n");
778   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
779     if (plugin_callbacks[event])
780       {
781         struct callback_info *ci;
782
783         fprintf (file, "%s\t", plugin_event_name[event]);
784
785         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
786           fprintf (file, "%s ", ci->plugin_name);
787
788         fprintf (file, "\n");
789       }
790 }
791
792
793 /* Dump active plugins to stderr.  */
794
795 void
796 debug_active_plugins (void)
797 {
798   dump_active_plugins (stderr);
799 }
800
801 /* The default version check. Compares every field in VERSION. */
802
803 bool
804 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
805                               struct plugin_gcc_version *plugin_version)
806 {
807   if (!gcc_version || !plugin_version)
808     return false;
809
810   if (strcmp (gcc_version->basever, plugin_version->basever))
811     return false;
812   if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
813     return false;
814   if (strcmp (gcc_version->devphase, plugin_version->devphase))
815     return false;
816   if (strcmp (gcc_version->revision, plugin_version->revision))
817     return false;
818   if (strcmp (gcc_version->configuration_arguments,
819               plugin_version->configuration_arguments))
820     return false;
821   return true;
822 }