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