OSDN Git Service

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