OSDN Git Service

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