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