1 /* Support for GCC plugin mechanism.
2    Copyright (C) 2009-2020 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         {
501           struct callback_info *new_callback;
502           if (!callback)
503             {
504               error ("plugin %s registered a null callback function "
505 		     "for event %s", plugin_name, plugin_event_name[event]);
506               return;
507             }
508           new_callback = XNEW (struct callback_info);
509           new_callback->plugin_name = plugin_name;
510           new_callback->func = callback;
511           new_callback->user_data = user_data;
512           new_callback->next = plugin_callbacks[event];
513           plugin_callbacks[event] = new_callback;
514         }
515         break;
516     }
517 }
518 
519 /* Remove a callback for EVENT which has been registered with for a plugin
520    PLUGIN_NAME.  Return PLUGEVT_SUCCESS if a matching callback was
521    found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching
522    callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid.  */
523 int
unregister_callback(const char * plugin_name,int event)524 unregister_callback (const char *plugin_name, int event)
525 {
526   struct callback_info *callback, **cbp;
527 
528   if (event >= event_last)
529     return PLUGEVT_NO_SUCH_EVENT;
530 
531   for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next)
532     if (strcmp (callback->plugin_name, plugin_name) == 0)
533       {
534 	*cbp = callback->next;
535 	return PLUGEVT_SUCCESS;
536       }
537   return PLUGEVT_NO_CALLBACK;
538 }
539 
540 /* Invoke all plugin callbacks registered with the specified event,
541    called from invoke_plugin_callbacks().  */
542 
543 int
invoke_plugin_callbacks_full(int event,void * gcc_data)544 invoke_plugin_callbacks_full (int event, void *gcc_data)
545 {
546   int retval = PLUGEVT_SUCCESS;
547 
548   timevar_push (TV_PLUGIN_RUN);
549 
550   switch (event)
551     {
552       case PLUGIN_EVENT_FIRST_DYNAMIC:
553       default:
554 	gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC);
555 	gcc_assert (event < event_last);
556       /* Fall through.  */
557       case PLUGIN_START_PARSE_FUNCTION:
558       case PLUGIN_FINISH_PARSE_FUNCTION:
559       case PLUGIN_FINISH_TYPE:
560       case PLUGIN_FINISH_DECL:
561       case PLUGIN_START_UNIT:
562       case PLUGIN_FINISH_UNIT:
563       case PLUGIN_PRE_GENERICIZE:
564       case PLUGIN_ATTRIBUTES:
565       case PLUGIN_PRAGMAS:
566       case PLUGIN_FINISH:
567       case PLUGIN_GGC_START:
568       case PLUGIN_GGC_MARKING:
569       case PLUGIN_GGC_END:
570       case PLUGIN_ALL_PASSES_START:
571       case PLUGIN_ALL_PASSES_END:
572       case PLUGIN_ALL_IPA_PASSES_START:
573       case PLUGIN_ALL_IPA_PASSES_END:
574       case PLUGIN_OVERRIDE_GATE:
575       case PLUGIN_PASS_EXECUTION:
576       case PLUGIN_EARLY_GIMPLE_PASSES_START:
577       case PLUGIN_EARLY_GIMPLE_PASSES_END:
578       case PLUGIN_NEW_PASS:
579       case PLUGIN_INCLUDE_FILE:
580         {
581           /* Iterate over every callback registered with this event and
582              call it.  */
583           struct callback_info *callback = plugin_callbacks[event];
584 
585 	  if (!callback)
586 	    retval = PLUGEVT_NO_CALLBACK;
587           for ( ; callback; callback = callback->next)
588             (*callback->func) (gcc_data, callback->user_data);
589         }
590         break;
591 
592       case PLUGIN_PASS_MANAGER_SETUP:
593       case PLUGIN_REGISTER_GGC_ROOTS:
594         gcc_assert (false);
595     }
596 
597   timevar_pop (TV_PLUGIN_RUN);
598   return retval;
599 }
600 
601 #ifdef ENABLE_PLUGIN
602 
603 /* Try to initialize PLUGIN. Return true if successful. */
604 
605 #ifdef __MINGW32__
606 
607 // Return a message string for last error or NULL if unknown. Must be freed
608 // with LocalFree().
609 static inline char *
win32_error_msg()610 win32_error_msg ()
611 {
612   char *msg;
613   return FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
614 			 FORMAT_MESSAGE_FROM_SYSTEM |
615 			 FORMAT_MESSAGE_IGNORE_INSERTS |
616 			 FORMAT_MESSAGE_MAX_WIDTH_MASK,
617 			 0,
618 			 GetLastError (),
619 			 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
620 			 (char*)&msg,
621 			 0,
622 			 0)
623     ? msg
624     : NULL;
625 }
626 
627 static bool
try_init_one_plugin(struct plugin_name_args * plugin)628 try_init_one_plugin (struct plugin_name_args *plugin)
629 {
630   HMODULE dl_handle;
631   plugin_init_func plugin_init;
632 
633   dl_handle = LoadLibrary (plugin->full_name);
634   if (!dl_handle)
635     {
636       char *err = win32_error_msg ();
637       error ("cannot load plugin %s\n%s", plugin->full_name, err);
638       LocalFree (err);
639       return false;
640     }
641 
642   /* Check the plugin license. Unlike the name suggests, GetProcAddress()
643      can be used for both functions and variables.  */
644   if (GetProcAddress (dl_handle, str_license) == NULL)
645     {
646       char *err = win32_error_msg ();
647       fatal_error (input_location,
648 		   "plugin %s is not licensed under a GPL-compatible license\n"
649 		   "%s", plugin->full_name, err);
650     }
651 
652   /* Unlike dlsym(), GetProcAddress() returns a pointer to a function so we
653      can cast directly without union tricks.  */
654   plugin_init = (plugin_init_func)
655     GetProcAddress (dl_handle, str_plugin_init_func_name);
656 
657   if (plugin_init == NULL)
658     {
659       char *err = win32_error_msg ();
660       FreeLibrary (dl_handle);
661       error ("cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
662              plugin->full_name, err);
663       LocalFree (err);
664       return false;
665     }
666 
667   /* Call the plugin-provided initialization routine with the arguments.  */
668   if ((*plugin_init) (plugin, &gcc_version))
669     {
670       FreeLibrary (dl_handle);
671       error ("fail to initialize plugin %s", plugin->full_name);
672       return false;
673     }
674   /* Leak dl_handle on purpose to ensure the plugin is loaded for the
675      entire run of the compiler. */
676   return true;
677 }
678 
679 #else // POSIX-like with dlopen()/dlsym().
680 
681 /* We need a union to cast dlsym return value to a function pointer
682    as ISO C forbids assignment between function pointer and 'void *'.
683    Use explicit union instead of __extension__(<union_cast>) for
684    portability.  */
685 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
686 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
687 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
688 
689 static bool
try_init_one_plugin(struct plugin_name_args * plugin)690 try_init_one_plugin (struct plugin_name_args *plugin)
691 {
692   void *dl_handle;
693   plugin_init_func plugin_init;
694   const char *err;
695   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
696 
697   /* We use RTLD_NOW to accelerate binding and detect any mismatch
698      between the API expected by the plugin and the GCC API; we use
699      RTLD_GLOBAL which is useful to plugins which themselves call
700      dlopen.  */
701   dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
702   if (!dl_handle)
703     {
704       error ("cannot load plugin %s: %s", plugin->full_name, dlerror ());
705       return false;
706     }
707 
708   /* Clear any existing error.  */
709   dlerror ();
710 
711   /* Check the plugin license.  */
712   if (dlsym (dl_handle, str_license) == NULL)
713     fatal_error (input_location,
714 		 "plugin %s is not licensed under a GPL-compatible license"
715 		 " %s", plugin->full_name, dlerror ());
716 
717   PTR_UNION_AS_VOID_PTR (plugin_init_union)
718     = dlsym (dl_handle, str_plugin_init_func_name);
719   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
720 
721   if ((err = dlerror ()) != NULL)
722     {
723       dlclose(dl_handle);
724       error ("cannot find %s in plugin %s: %s", str_plugin_init_func_name,
725              plugin->full_name, err);
726       return false;
727     }
728 
729   /* Call the plugin-provided initialization routine with the arguments.  */
730   if ((*plugin_init) (plugin, &gcc_version))
731     {
732       dlclose(dl_handle);
733       error ("failed to initialize plugin %s", plugin->full_name);
734       return false;
735     }
736   /* leak dl_handle on purpose to ensure the plugin is loaded for the
737      entire run of the compiler. */
738   return true;
739 }
740 #endif
741 
742 /* Routine to dlopen and initialize one plugin. This function is passed to
743    (and called by) the hash table traverse routine. Return 1 for the
744    htab_traverse to continue scan, 0 to stop.
745 
746    SLOT - slot of the hash table element
747    INFO - auxiliary pointer handed to hash table traverse routine
748           (unused in this function)  */
749 
750 static int
init_one_plugin(void ** slot,void * ARG_UNUSED (info))751 init_one_plugin (void **slot, void * ARG_UNUSED (info))
752 {
753   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
754   bool ok = try_init_one_plugin (plugin);
755   if (!ok)
756     {
757       htab_remove_elt_with_hash (plugin_name_args_tab, plugin->base_name,
758 				 htab_hash_string (plugin->base_name));
759       XDELETE (plugin);
760     }
761   return 1;
762 }
763 
764 #endif	/* ENABLE_PLUGIN  */
765 
766 /* Main plugin initialization function.  Called from compile_file() in
767    toplev.c.  */
768 
769 void
initialize_plugins(void)770 initialize_plugins (void)
771 {
772   /* If no plugin was specified in the command-line, simply return.  */
773   if (!plugin_name_args_tab)
774     return;
775 
776   timevar_push (TV_PLUGIN_INIT);
777 
778 #ifdef ENABLE_PLUGIN
779   /* Traverse and initialize each plugin specified in the command-line.  */
780   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
781 #endif
782 
783   timevar_pop (TV_PLUGIN_INIT);
784 }
785 
786 /* Release memory used by one plugin. */
787 
788 static int
finalize_one_plugin(void ** slot,void * ARG_UNUSED (info))789 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
790 {
791   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
792   XDELETE (plugin);
793   return 1;
794 }
795 
796 /* Free memory allocated by the plugin system. */
797 
798 void
finalize_plugins(void)799 finalize_plugins (void)
800 {
801   if (!plugin_name_args_tab)
802     return;
803 
804   /* We can now delete the plugin_name_args object as it will no longer
805      be used. Note that base_name and argv fields (both of which were also
806      dynamically allocated) are not freed as they could still be used by
807      the plugin code.  */
808 
809   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
810 
811   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
812   htab_delete (plugin_name_args_tab);
813   plugin_name_args_tab = NULL;
814 }
815 
816 /* Used to pass options to htab_traverse callbacks. */
817 
818 struct print_options
819 {
820   FILE *file;
821   const char *indent;
822 };
823 
824 /* Print the version of one plugin. */
825 
826 static int
print_version_one_plugin(void ** slot,void * data)827 print_version_one_plugin (void **slot, void *data)
828 {
829   struct print_options *opt = (struct print_options *) data;
830   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
831   const char *version = plugin->version ? plugin->version : "Unknown version.";
832 
833   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
834   return 1;
835 }
836 
837 /* Print the version of each plugin. */
838 
839 void
print_plugins_versions(FILE * file,const char * indent)840 print_plugins_versions (FILE *file, const char *indent)
841 {
842   struct print_options opt;
843   opt.file = file;
844   opt.indent = indent;
845   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
846     return;
847 
848   fprintf (file, "%sVersions of loaded plugins:\n", indent);
849   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
850 }
851 
852 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
853    argument to htab_traverse_noresize. */
854 
855 static int
print_help_one_plugin(void ** slot,void * data)856 print_help_one_plugin (void **slot, void *data)
857 {
858   struct print_options *opt = (struct print_options *) data;
859   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
860   const char *help = plugin->help ? plugin->help : "No help available .";
861 
862   char *dup = xstrdup (help);
863   char *p, *nl;
864   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
865 
866   for (p = nl = dup; nl; p = nl)
867     {
868       nl = strchr (nl, '\n');
869       if (nl)
870 	{
871 	  *nl = '\0';
872 	  nl++;
873 	}
874       fprintf (opt->file, "   %s %s\n", opt->indent, p);
875     }
876 
877   free (dup);
878   return 1;
879 }
880 
881 /* Print help for each plugin. The output goes to FILE and every line starts
882    with INDENT. */
883 
884 void
print_plugins_help(FILE * file,const char * indent)885 print_plugins_help (FILE *file, const char *indent)
886 {
887   struct print_options opt;
888   opt.file = file;
889   opt.indent = indent;
890   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
891     return;
892 
893   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
894   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
895 }
896 
897 
898 /* Return true if plugins have been loaded.  */
899 
900 bool
plugins_active_p(void)901 plugins_active_p (void)
902 {
903   int event;
904 
905   for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
906     if (plugin_callbacks[event])
907       return true;
908 
909   return false;
910 }
911 
912 
913 /* Dump to FILE the names and associated events for all the active
914    plugins.  */
915 
916 DEBUG_FUNCTION void
dump_active_plugins(FILE * file)917 dump_active_plugins (FILE *file)
918 {
919   int event;
920 
921   if (!plugins_active_p ())
922     return;
923 
924   fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
925   for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
926     if (plugin_callbacks[event])
927       {
928 	struct callback_info *ci;
929 
930 	fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]);
931 
932 	for (ci = plugin_callbacks[event]; ci; ci = ci->next)
933 	  fprintf (file, " %s", ci->plugin_name);
934 
935 	putc ('\n', file);
936       }
937 }
938 
939 
940 /* Dump active plugins to stderr.  */
941 
942 DEBUG_FUNCTION void
debug_active_plugins(void)943 debug_active_plugins (void)
944 {
945   dump_active_plugins (stderr);
946 }
947 
948 /* Give a warning if plugins are present, before an ICE message asking
949    to submit a bug report.  */
950 
951 void
warn_if_plugins(void)952 warn_if_plugins (void)
953 {
954   if (plugins_active_p ())
955     {
956       fnotice (stderr, "*** WARNING *** there are active plugins, do not report"
957 	       " this as a bug unless you can reproduce it without enabling"
958 	       " any plugins.\n");
959       dump_active_plugins (stderr);
960     }
961 
962 }
963 
964 /* The default version check. Compares every field in VERSION. */
965 
966 bool
plugin_default_version_check(struct plugin_gcc_version * gcc_version,struct plugin_gcc_version * plugin_version)967 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
968 			      struct plugin_gcc_version *plugin_version)
969 {
970   if (!gcc_version || !plugin_version)
971     return false;
972 
973   if (strcmp (gcc_version->basever, plugin_version->basever))
974     return false;
975   if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
976     return false;
977   if (strcmp (gcc_version->devphase, plugin_version->devphase))
978     return false;
979   if (strcmp (gcc_version->revision, plugin_version->revision))
980     return false;
981   if (strcmp (gcc_version->configuration_arguments,
982 	      plugin_version->configuration_arguments))
983     return false;
984   return true;
985 }
986 
987 
988 /* Return the current value of event_last, so that plugins which provide
989    additional functionality for events for the benefit of high-level plugins
990    know how many valid entries plugin_event_name holds.  */
991 
992 int
get_event_last(void)993 get_event_last (void)
994 {
995   return event_last;
996 }
997 
998 
999 /* Retrieve the default plugin directory.  The gcc driver should have passed
1000    it as -iplugindir <dir> to the cc1 program, and it is queriable through the
1001    -print-file-name=plugin option to gcc.  */
1002 const char*
default_plugin_dir_name(void)1003 default_plugin_dir_name (void)
1004 {
1005   if (!plugindir_string)
1006     fatal_error (input_location,
1007 		 "%<-iplugindir%> <dir> option not passed from the gcc driver");
1008   return plugindir_string;
1009 }
1010