OSDN Git Service

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