OSDN Git Service

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