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