OSDN Git Service

2009-05-26 Basile Starynkevitch <basile@starynkevitch.net>
[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 #include "ggc.h"
42
43 #ifdef ENABLE_PLUGIN
44 #include "plugin-version.h"
45 #endif
46
47 /* Event names as strings.  Keep in sync with enum plugin_event.  */
48 const char *plugin_event_name[] =
49 {
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"
61 };
62
63 /* Hash table for the plugin_name_args objects created during command-line
64    parsing.  */
65 static htab_t plugin_name_args_tab = NULL;
66
67 /* List node for keeping track of plugin-registered callback.  */
68 struct callback_info
69 {
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;
74 };
75
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 };
78
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
86 {
87   struct opt_pass *pass;
88   struct pass_list_node *next;
89 };
90
91 static struct pass_list_node *added_pass_nodes = NULL;
92 static struct pass_list_node *prev_added_pass_node;
93
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";
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
285 /* Insert the plugin pass at the proper position. Return true if the pass 
286    is successfully added.
287
288    PLUGIN_PASS_INFO - new pass to be inserted
289    PASS_LIST        - root of the pass list to insert the new pass to  */
290
291 static bool
292 position_pass (struct plugin_pass *plugin_pass_info,
293                struct opt_pass **pass_list)
294 {
295   struct opt_pass *pass = *pass_list, *prev_pass = NULL;
296   bool success = false;
297
298   for ( ; pass; prev_pass = pass, pass = pass->next)
299     {
300       /* Check if the current pass is of the same type as the new pass and
301          matches the name and the instance number of the reference pass.  */
302       if (pass->type == plugin_pass_info->pass->type
303           && pass->name
304           && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
305           && ((plugin_pass_info->ref_pass_instance_number == 0)
306               || (plugin_pass_info->ref_pass_instance_number ==
307                   pass->static_pass_number)
308               || (plugin_pass_info->ref_pass_instance_number == 1
309                   && pass->todo_flags_start & TODO_mark_first_instance)))
310         {
311           struct opt_pass *new_pass = plugin_pass_info->pass;
312           struct pass_list_node *new_pass_node;
313
314           /* The following code (if-statement) is adopted from next_pass_1.  */
315           if (new_pass->static_pass_number)
316             {
317               new_pass = XNEW (struct opt_pass);
318               memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
319               new_pass->next = NULL;
320
321               new_pass->todo_flags_start &= ~TODO_mark_first_instance;
322
323               plugin_pass_info->pass->static_pass_number -= 1;
324               new_pass->static_pass_number =
325                   -plugin_pass_info->pass->static_pass_number;
326             }
327           else
328             {
329               new_pass->todo_flags_start |= TODO_mark_first_instance;
330               new_pass->static_pass_number = -1;
331             }
332
333           /* Insert the new pass instance based on the positioning op.  */
334           switch (plugin_pass_info->pos_op)
335             {
336               case PASS_POS_INSERT_AFTER:
337                 new_pass->next = pass->next;
338                 pass->next = new_pass;
339                 break;
340               case PASS_POS_INSERT_BEFORE:
341                 new_pass->next = pass;
342                 if (prev_pass)
343                   prev_pass->next = new_pass;
344                 else
345                   *pass_list = new_pass;
346                 break;
347               case PASS_POS_REPLACE:
348                 new_pass->next = pass->next;
349                 if (prev_pass)
350                   prev_pass->next = new_pass;
351                 else
352                   *pass_list = new_pass;
353                 new_pass->sub = pass->sub;
354                 new_pass->tv_id = pass->tv_id;
355                 pass = new_pass;
356                 break;
357               default:
358                 error ("Invalid pass positioning operation");
359                 return false;
360             }
361
362           /* Save the newly added pass (instance) in the added_pass_nodes
363              list so that we can register its dump file later. Note that
364              we cannot register the dump file now because doing so will modify
365              the static_pass_number of the opt_pass object and therefore
366              mess up the dump file name of future instances.  */
367           new_pass_node = XCNEW (struct pass_list_node);
368           new_pass_node->pass = new_pass;
369           if (!added_pass_nodes)
370             added_pass_nodes = new_pass_node;
371           else
372             prev_added_pass_node->next = new_pass_node;
373           prev_added_pass_node = new_pass_node;
374
375           success = true;
376         }
377
378       if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
379         success = true;
380     }
381
382   return success;
383 }
384
385
386 /* Hook into the pass lists (trees) a new pass registered by a plugin.
387
388    PLUGIN_NAME - display name for the plugin
389    PASS_INFO   - plugin pass information that specifies the opt_pass object,
390                  reference pass, instance number, and how to position
391                  the pass  */
392
393 static void
394 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
395 {
396   if (!pass_info->pass)
397     {
398       error ("No pass specified when registering a new pass in plugin %s",
399              plugin_name);
400       return;
401     }
402
403   if (!pass_info->reference_pass_name)
404     {
405       error ("No reference pass specified for positioning the pass "
406              " from plugin %s", plugin_name);
407       return;
408     }
409
410   /* Try to insert the new pass to the pass lists. We need to check all
411      three lists as the reference pass could be in one (or all) of them.  */
412   if (!position_pass (pass_info, &all_lowering_passes)
413       && !position_pass (pass_info, &all_ipa_passes)
414       && !position_pass (pass_info, &all_passes))
415     error ("Failed to position pass %s registered by plugin %s. "
416            "Cannot find the (specified instance of) reference pass %s",
417            pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
418   else
419     {
420       /* OK, we have successfully inserted the new pass. We need to register
421          the dump files for the newly added pass and its duplicates (if any).
422          Because the registration of plugin passes happens after the
423          command-line options are parsed, the options that specify single
424          pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
425          plugin passes. Therefore we currently can only enable dumping of
426          new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
427          are specified. While doing so, we also delete the pass_list_node
428          objects created during pass positioning.  */
429       while (added_pass_nodes)
430         {
431           struct pass_list_node *next_node = added_pass_nodes->next;
432           enum tree_dump_index tdi;
433           register_one_dump_file (added_pass_nodes->pass);
434           if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
435               || added_pass_nodes->pass->type == IPA_PASS)
436             tdi = TDI_ipa_all;
437           else if (added_pass_nodes->pass->type == GIMPLE_PASS)
438             tdi = TDI_tree_all;
439           else
440             tdi = TDI_rtl_all;
441           /* Check if dump-all flag is specified.  */
442           if (get_dump_file_info (tdi)->state)
443             get_dump_file_info (added_pass_nodes->pass->static_pass_number)
444                 ->state = get_dump_file_info (tdi)->state;
445           XDELETE (added_pass_nodes);
446           added_pass_nodes = next_node;
447         }
448     }
449 }
450
451
452 /* Register additional plugin information. NAME is the name passed to
453    plugin_init. INFO is the information that should be registered. */
454
455 static void
456 register_plugin_info (const char* name, struct plugin_info *info)
457 {
458   void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
459   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
460   plugin->version = info->version;
461   plugin->help = info->help;
462 }
463
464 /* Called from the plugin's initialization code. Register a single callback.
465    This function can be called multiple times.
466
467    PLUGIN_NAME - display name for this plugin
468    EVENT       - which event the callback is for
469    CALLBACK    - the callback to be called at the event
470    USER_DATA   - plugin-provided data   */
471
472 void
473 register_callback (const char *plugin_name,
474                    enum plugin_event event,
475                    plugin_callback_func callback,
476                    void *user_data)
477 {
478   switch (event)
479     {
480       case PLUGIN_PASS_MANAGER_SETUP:
481         gcc_assert (!callback);
482         register_pass (plugin_name, (struct plugin_pass *) user_data);
483         break;
484       case PLUGIN_INFO:
485         gcc_assert (!callback);
486         register_plugin_info (plugin_name, (struct plugin_info *) user_data);
487         break;
488       case PLUGIN_REGISTER_GGC_ROOTS:
489         gcc_assert (!callback);
490         ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
491         break;
492       case PLUGIN_FINISH_TYPE:
493       case PLUGIN_FINISH_UNIT:
494       case PLUGIN_CXX_CP_PRE_GENERICIZE:
495       case PLUGIN_GGC_START:
496       case PLUGIN_GGC_MARKING:
497       case PLUGIN_GGC_END:
498       case PLUGIN_ATTRIBUTES:
499       case PLUGIN_FINISH:
500         {
501           struct callback_info *new_callback;
502           if (!callback)
503             {
504               error ("Plugin %s registered a null callback function "
505                      "for event %s", plugin_name, plugin_event_name[event]);
506               return;
507             }
508           new_callback = XNEW (struct callback_info);
509           new_callback->plugin_name = plugin_name;
510           new_callback->func = callback;
511           new_callback->user_data = user_data;
512           new_callback->next = plugin_callbacks[event];
513           plugin_callbacks[event] = new_callback;
514         }
515         break;
516       case PLUGIN_EVENT_LAST:
517       default:
518         error ("Unkown callback event registered by plugin %s",
519                plugin_name);
520     }
521 }
522
523
524 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
525    the specified event.
526
527    EVENT    - the event identifier
528    GCC_DATA - event-specific data provided by the compiler  */
529
530 void
531 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
532 {
533   timevar_push (TV_PLUGIN_RUN);
534
535   switch (event)
536     {
537       case PLUGIN_FINISH_TYPE:
538       case PLUGIN_FINISH_UNIT:
539       case PLUGIN_CXX_CP_PRE_GENERICIZE:
540       case PLUGIN_ATTRIBUTES:
541       case PLUGIN_FINISH:
542       case PLUGIN_GGC_START:
543       case PLUGIN_GGC_MARKING:
544       case PLUGIN_GGC_END:
545         {
546           /* Iterate over every callback registered with this event and
547              call it.  */
548           struct callback_info *callback = plugin_callbacks[event];
549           for ( ; callback; callback = callback->next)
550             (*callback->func) (gcc_data, callback->user_data);
551         }
552         break;
553
554       case PLUGIN_PASS_MANAGER_SETUP:
555       case PLUGIN_EVENT_LAST:
556       case PLUGIN_REGISTER_GGC_ROOTS:
557       default:
558         gcc_assert (false);
559     }
560
561   timevar_pop (TV_PLUGIN_RUN);
562 }
563
564 #ifdef ENABLE_PLUGIN
565 /* We need a union to cast dlsym return value to a function pointer
566    as ISO C forbids assignment between function pointer and 'void *'.
567    Use explicit union instead of __extension__(<union_cast>) for
568    portability.  */
569 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
570 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
571 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
572
573 /* Try to initialize PLUGIN. Return true if successful. */
574
575 static bool
576 try_init_one_plugin (struct plugin_name_args *plugin)
577 {
578   void *dl_handle;
579   plugin_init_func plugin_init;
580   char *err;
581   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
582
583   dl_handle = dlopen (plugin->full_name, RTLD_NOW);
584   if (!dl_handle)
585     {
586       error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
587       return false;
588     }
589
590   /* Clear any existing error.  */
591   dlerror ();
592
593   PTR_UNION_AS_VOID_PTR (plugin_init_union) =
594       dlsym (dl_handle, str_plugin_init_func_name);
595   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
596
597   if ((err = dlerror ()) != NULL)
598     {
599       error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
600              plugin->full_name, err);
601       return false;
602     }
603
604   /* Call the plugin-provided initialization routine with the arguments.  */
605   if ((*plugin_init) (plugin, &gcc_version))
606     {
607       error ("Fail to initialize plugin %s", plugin->full_name);
608       return false;
609     }
610
611   return true;
612 }
613
614
615 /* Routine to dlopen and initialize one plugin. This function is passed to
616    (and called by) the hash table traverse routine. Return 1 for the
617    htab_traverse to continue scan, 0 to stop.
618
619    SLOT - slot of the hash table element
620    INFO - auxiliary pointer handed to hash table traverse routine
621           (unused in this function)  */
622
623 static int
624 init_one_plugin (void **slot, void * ARG_UNUSED (info))
625 {
626   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
627   bool ok = try_init_one_plugin (plugin);
628   if (!ok)
629     {
630       htab_remove_elt (plugin_name_args_tab, plugin->base_name);
631       XDELETE (plugin);
632     }
633   return 1;
634 }
635
636 #endif  /* ENABLE_PLUGIN  */
637
638 /* Main plugin initialization function.  Called from compile_file() in
639    toplev.c.  */
640
641 void
642 initialize_plugins (void)
643 {
644   /* If no plugin was specified in the command-line, simply return.  */
645   if (!plugin_name_args_tab)
646     return;
647
648   timevar_push (TV_PLUGIN_INIT);
649  
650 #ifdef ENABLE_PLUGIN
651   /* Traverse and initialize each plugin specified in the command-line.  */
652   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
653 #endif
654
655   timevar_pop (TV_PLUGIN_INIT);
656 }
657
658 /* Release memory used by one plugin. */
659
660 static int
661 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
662 {
663   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
664   XDELETE (plugin);
665   return 1;
666 }
667
668 /* Free memory allocated by the plugin system. */
669
670 void
671 finalize_plugins (void)
672 {
673   if (!plugin_name_args_tab)
674     return;
675
676   /* We can now delete the plugin_name_args object as it will no longer
677      be used. Note that base_name and argv fields (both of which were also
678      dynamically allocated) are not freed as they could still be used by
679      the plugin code.  */
680
681   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
682
683   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
684   htab_delete (plugin_name_args_tab);
685   plugin_name_args_tab = NULL;
686 }
687
688 /* Used to pass options to htab_traverse callbacks. */
689
690 struct print_options
691 {
692   FILE *file;
693   const char *indent;
694 };
695
696 /* Print the version of one plugin. */
697
698 static int
699 print_version_one_plugin (void **slot, void *data)
700 {
701   struct print_options *opt = (struct print_options *) data;
702   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
703   const char *version = plugin->version ? plugin->version : "Unknown version.";
704
705   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
706   return 1;
707 }
708
709 /* Print the version of each plugin. */
710
711 void
712 print_plugins_versions (FILE *file, const char *indent)
713 {
714   struct print_options opt;
715   opt.file = file;
716   opt.indent = indent;
717   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
718     return;
719
720   fprintf (file, "%sVersions of loaded plugins:\n", indent);
721   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
722 }
723
724 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
725    argument to htab_traverse_noresize. */
726
727 static int
728 print_help_one_plugin (void **slot, void *data)
729 {
730   struct print_options *opt = (struct print_options *) data;
731   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
732   const char *help = plugin->help ? plugin->help : "No help available .";
733
734   char *dup = xstrdup (help);
735   char *p, *nl;
736   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
737
738   for (p = nl = dup; nl; p = nl)
739     {
740       nl = strchr (nl, '\n');
741       if (nl)
742         {
743           *nl = '\0';
744           nl++;
745         }
746       fprintf (opt->file, "   %s %s\n", opt->indent, p);
747     }
748
749   free (dup);
750   return 1;
751 }
752
753 /* Print help for each plugin. The output goes to FILE and every line starts
754    with INDENT. */
755
756 void
757 print_plugins_help (FILE *file, const char *indent)
758 {
759   struct print_options opt;
760   opt.file = file;
761   opt.indent = indent;
762   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
763     return;
764
765   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
766   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
767 }
768
769
770 /* Return true if plugins have been loaded.  */
771
772 bool
773 plugins_active_p (void)
774 {
775   int event;
776
777   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
778     if (plugin_callbacks[event])
779       return true;
780
781   return false;
782 }
783
784
785 /* Dump to FILE the names and associated events for all the active
786    plugins.  */
787
788 void
789 dump_active_plugins (FILE *file)
790 {
791   int event;
792
793   if (!plugins_active_p ())
794     return;
795
796   fprintf (stderr, "Event\t\t\tPlugins\n");
797   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
798     if (plugin_callbacks[event])
799       {
800         struct callback_info *ci;
801
802         fprintf (file, "%s\t", plugin_event_name[event]);
803
804         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
805           fprintf (file, "%s ", ci->plugin_name);
806
807         fprintf (file, "\n");
808       }
809 }
810
811
812 /* Dump active plugins to stderr.  */
813
814 void
815 debug_active_plugins (void)
816 {
817   dump_active_plugins (stderr);
818 }
819
820 /* The default version check. Compares every field in VERSION. */
821
822 bool
823 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
824                               struct plugin_gcc_version *plugin_version)
825 {
826   if (!gcc_version || !plugin_version)
827     return false;
828
829   if (strcmp (gcc_version->basever, plugin_version->basever))
830     return false;
831   if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
832     return false;
833   if (strcmp (gcc_version->devphase, plugin_version->devphase))
834     return false;
835   if (strcmp (gcc_version->revision, plugin_version->revision))
836     return false;
837   if (strcmp (gcc_version->configuration_arguments,
838               plugin_version->configuration_arguments))
839     return false;
840   return true;
841 }