Fix PR42732.
[official-gcc/Ramakrishna.git] / gcc / plugin.c
blobc43e0c844a136ba2bfa6b3034acc7d9ab2091c38
1 /* Support for GCC plugin mechanism.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 /* This file contains the support for GCC plugin mechanism based on the
21 APIs described in doc/plugin.texi. */
23 #include "config.h"
24 #include "system.h"
26 /* If plugin support is not enabled, do not try to execute any code
27 that may reference libdl. The generic code is still compiled in to
28 avoid including too many conditional compilation paths in the rest
29 of the compiler. */
30 #ifdef ENABLE_PLUGIN
31 #include <dlfcn.h>
32 #endif
34 #include "coretypes.h"
35 #include "toplev.h"
36 #include "tree.h"
37 #include "tree-pass.h"
38 #include "intl.h"
39 #include "plugin.h"
40 #include "timevar.h"
41 #include "ggc.h"
43 #ifdef ENABLE_PLUGIN
44 #include "plugin-version.h"
45 #endif
47 /* Event names as strings. Keep in sync with enum plugin_event. */
48 const char *plugin_event_name[] =
50 "PLUGIN_PASS_MANAGER_SETUP",
51 "PLUGIN_FINISH_TYPE",
52 "PLUGIN_FINISH_UNIT",
53 "PLUGIN_CXX_CP_PRE_GENERICIZE",
54 "PLUGIN_FINISH",
55 "PLUGIN_INFO",
56 "PLUGIN_GGC_START",
57 "PLUGIN_GGC_MARKING",
58 "PLUGIN_GGC_END",
59 "PLUGIN_REGISTER_GGC_ROOTS",
60 "PLUGIN_REGISTER_GGC_CACHES",
61 "PLUGIN_ATTRIBUTES",
62 "PLUGIN_START_UNIT",
63 "PLUGIN_PRAGMAS",
64 "PLUGIN_EVENT_LAST"
67 /* A printf format large enough for the largest event above. */
68 #define FMT_FOR_PLUGIN_EVENT "%-26s"
70 /* Hash table for the plugin_name_args objects created during command-line
71 parsing. */
72 static htab_t plugin_name_args_tab = NULL;
74 /* List node for keeping track of plugin-registered callback. */
75 struct callback_info
77 const char *plugin_name; /* Name of plugin that registers the callback. */
78 plugin_callback_func func; /* Callback to be called. */
79 void *user_data; /* plugin-specified data. */
80 struct callback_info *next;
83 /* An array of lists of 'callback_info' objects indexed by the event id. */
84 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
87 #ifdef ENABLE_PLUGIN
88 /* Each plugin should define an initialization function with exactly
89 this name. */
90 static const char *str_plugin_init_func_name = "plugin_init";
92 /* Each plugin should define this symbol to assert that it is
93 distributed under a GPL-compatible license. */
94 static const char *str_license = "plugin_is_GPL_compatible";
95 #endif
97 /* Helper function for the hash table that compares the base_name of the
98 existing entry (S1) with the given string (S2). */
100 static int
101 htab_str_eq (const void *s1, const void *s2)
103 const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
104 return !strcmp (plugin->base_name, (const char *) s2);
108 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
109 return NAME. */
111 static char *
112 get_plugin_base_name (const char *full_name)
114 /* First get the base name part of the full-path name, i.e. NAME.so. */
115 char *base_name = xstrdup (lbasename (full_name));
117 /* Then get rid of '.so' part of the name. */
118 strip_off_ending (base_name, strlen (base_name));
120 return base_name;
124 /* Create a plugin_name_args object for the give plugin and insert it to
125 the hash table. This function is called when -fplugin=/path/to/NAME.so
126 option is processed. */
128 void
129 add_new_plugin (const char* plugin_name)
131 struct plugin_name_args *plugin;
132 void **slot;
133 char *base_name = get_plugin_base_name (plugin_name);
135 /* If this is the first -fplugin= option we encounter, create
136 'plugin_name_args_tab' hash table. */
137 if (!plugin_name_args_tab)
138 plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
139 NULL);
141 slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
143 /* If the same plugin (name) has been specified earlier, either emit an
144 error or a warning message depending on if they have identical full
145 (path) names. */
146 if (*slot)
148 plugin = (struct plugin_name_args *) *slot;
149 if (strcmp (plugin->full_name, plugin_name))
150 error ("Plugin %s was specified with different paths:\n%s\n%s",
151 plugin->base_name, plugin->full_name, plugin_name);
152 return;
155 plugin = XCNEW (struct plugin_name_args);
156 plugin->base_name = base_name;
157 plugin->full_name = plugin_name;
159 *slot = plugin;
163 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
164 'plugin_argument' object for the parsed key-value pair. ARG is
165 the <name>-<key>[=<value>] part of the option. */
167 void
168 parse_plugin_arg_opt (const char *arg)
170 size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
171 const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
172 char *name, *key, *value;
173 void **slot;
174 bool name_parsed = false, key_parsed = false;
176 /* Iterate over the ARG string and identify the starting character position
177 of 'name', 'key', and 'value' and their lengths. */
178 for (ptr = arg; *ptr; ++ptr)
180 /* Only the first '-' encountered is considered a separator between
181 'name' and 'key'. All the subsequent '-'s are considered part of
182 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
183 the plugin name is 'foo' and the key is 'bar-primary-key'. */
184 if (*ptr == '-' && !name_parsed)
186 name_len = len;
187 len = 0;
188 key_start = ptr + 1;
189 name_parsed = true;
190 continue;
192 else if (*ptr == '=')
194 if (key_parsed)
196 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
197 arg);
198 return;
200 key_len = len;
201 len = 0;
202 value_start = ptr + 1;
203 key_parsed = true;
204 continue;
206 else
207 ++len;
210 if (!key_start)
212 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
213 arg);
214 return;
217 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
218 Otherwise, it is the VALUE_LEN. */
219 if (!value_start)
220 key_len = len;
221 else
222 value_len = len;
224 name = XNEWVEC (char, name_len + 1);
225 strncpy (name, name_start, name_len);
226 name[name_len] = '\0';
228 /* Check if the named plugin has already been specified earlier in the
229 command-line. */
230 if (plugin_name_args_tab
231 && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
232 != NULL))
234 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
236 key = XNEWVEC (char, key_len + 1);
237 strncpy (key, key_start, key_len);
238 key[key_len] = '\0';
239 if (value_start)
241 value = XNEWVEC (char, value_len + 1);
242 strncpy (value, value_start, value_len);
243 value[value_len] = '\0';
245 else
246 value = NULL;
248 /* Create a plugin_argument object for the parsed key-value pair.
249 If there are already arguments for this plugin, we will need to
250 adjust the argument array size by creating a new array and deleting
251 the old one. If the performance ever becomes an issue, we can
252 change the code by pre-allocating a larger array first. */
253 if (plugin->argc > 0)
255 struct plugin_argument *args = XNEWVEC (struct plugin_argument,
256 plugin->argc + 1);
257 memcpy (args, plugin->argv,
258 sizeof (struct plugin_argument) * plugin->argc);
259 XDELETEVEC (plugin->argv);
260 plugin->argv = args;
261 ++plugin->argc;
263 else
265 gcc_assert (plugin->argv == NULL);
266 plugin->argv = XNEWVEC (struct plugin_argument, 1);
267 plugin->argc = 1;
270 plugin->argv[plugin->argc - 1].key = key;
271 plugin->argv[plugin->argc - 1].value = value;
273 else
274 error ("Plugin %s should be specified before -fplugin-arg-%s "
275 "in the command line", name, arg);
277 /* We don't need the plugin's name anymore. Just release it. */
278 XDELETEVEC (name);
281 /* Register additional plugin information. NAME is the name passed to
282 plugin_init. INFO is the information that should be registered. */
284 static void
285 register_plugin_info (const char* name, struct plugin_info *info)
287 void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
288 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
289 plugin->version = info->version;
290 plugin->help = info->help;
293 /* Called from the plugin's initialization code. Register a single callback.
294 This function can be called multiple times.
296 PLUGIN_NAME - display name for this plugin
297 EVENT - which event the callback is for
298 CALLBACK - the callback to be called at the event
299 USER_DATA - plugin-provided data */
301 void
302 register_callback (const char *plugin_name,
303 enum plugin_event event,
304 plugin_callback_func callback,
305 void *user_data)
307 switch (event)
309 case PLUGIN_PASS_MANAGER_SETUP:
310 gcc_assert (!callback);
311 register_pass ((struct register_pass_info *) user_data);
312 break;
313 case PLUGIN_INFO:
314 gcc_assert (!callback);
315 register_plugin_info (plugin_name, (struct plugin_info *) user_data);
316 break;
317 case PLUGIN_REGISTER_GGC_ROOTS:
318 gcc_assert (!callback);
319 ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
320 break;
321 case PLUGIN_REGISTER_GGC_CACHES:
322 gcc_assert (!callback);
323 ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data);
324 break;
325 case PLUGIN_FINISH_TYPE:
326 case PLUGIN_START_UNIT:
327 case PLUGIN_FINISH_UNIT:
328 case PLUGIN_CXX_CP_PRE_GENERICIZE:
329 case PLUGIN_GGC_START:
330 case PLUGIN_GGC_MARKING:
331 case PLUGIN_GGC_END:
332 case PLUGIN_ATTRIBUTES:
333 case PLUGIN_PRAGMAS:
334 case PLUGIN_FINISH:
336 struct callback_info *new_callback;
337 if (!callback)
339 error ("Plugin %s registered a null callback function "
340 "for event %s", plugin_name, plugin_event_name[event]);
341 return;
343 new_callback = XNEW (struct callback_info);
344 new_callback->plugin_name = plugin_name;
345 new_callback->func = callback;
346 new_callback->user_data = user_data;
347 new_callback->next = plugin_callbacks[event];
348 plugin_callbacks[event] = new_callback;
350 break;
351 case PLUGIN_EVENT_LAST:
352 default:
353 error ("Unknown callback event registered by plugin %s",
354 plugin_name);
359 /* Called from inside GCC. Invoke all plug-in callbacks registered with
360 the specified event.
362 EVENT - the event identifier
363 GCC_DATA - event-specific data provided by the compiler */
365 void
366 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
368 timevar_push (TV_PLUGIN_RUN);
370 switch (event)
372 case PLUGIN_FINISH_TYPE:
373 case PLUGIN_START_UNIT:
374 case PLUGIN_FINISH_UNIT:
375 case PLUGIN_CXX_CP_PRE_GENERICIZE:
376 case PLUGIN_ATTRIBUTES:
377 case PLUGIN_PRAGMAS:
378 case PLUGIN_FINISH:
379 case PLUGIN_GGC_START:
380 case PLUGIN_GGC_MARKING:
381 case PLUGIN_GGC_END:
383 /* Iterate over every callback registered with this event and
384 call it. */
385 struct callback_info *callback = plugin_callbacks[event];
386 for ( ; callback; callback = callback->next)
387 (*callback->func) (gcc_data, callback->user_data);
389 break;
391 case PLUGIN_PASS_MANAGER_SETUP:
392 case PLUGIN_EVENT_LAST:
393 case PLUGIN_REGISTER_GGC_ROOTS:
394 case PLUGIN_REGISTER_GGC_CACHES:
395 default:
396 gcc_assert (false);
399 timevar_pop (TV_PLUGIN_RUN);
402 #ifdef ENABLE_PLUGIN
403 /* We need a union to cast dlsym return value to a function pointer
404 as ISO C forbids assignment between function pointer and 'void *'.
405 Use explicit union instead of __extension__(<union_cast>) for
406 portability. */
407 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
408 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
409 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
411 /* Try to initialize PLUGIN. Return true if successful. */
413 static bool
414 try_init_one_plugin (struct plugin_name_args *plugin)
416 void *dl_handle;
417 plugin_init_func plugin_init;
418 const char *err;
419 PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
421 /* We use RTLD_NOW to accelerate binding and detect any mismatch
422 between the API expected by the plugin and the GCC API; we use
423 RTLD_GLOBAL which is useful to plugins which themselves call
424 dlopen. */
425 dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
426 if (!dl_handle)
428 error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
429 return false;
432 /* Clear any existing error. */
433 dlerror ();
435 /* Check the plugin license. */
436 if (dlsym (dl_handle, str_license) == NULL)
437 fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
438 "%s", plugin->full_name, dlerror ());
440 PTR_UNION_AS_VOID_PTR (plugin_init_union) =
441 dlsym (dl_handle, str_plugin_init_func_name);
442 plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
444 if ((err = dlerror ()) != NULL)
446 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
447 plugin->full_name, err);
448 return false;
451 /* Call the plugin-provided initialization routine with the arguments. */
452 if ((*plugin_init) (plugin, &gcc_version))
454 error ("Fail to initialize plugin %s", plugin->full_name);
455 return false;
458 return true;
462 /* Routine to dlopen and initialize one plugin. This function is passed to
463 (and called by) the hash table traverse routine. Return 1 for the
464 htab_traverse to continue scan, 0 to stop.
466 SLOT - slot of the hash table element
467 INFO - auxiliary pointer handed to hash table traverse routine
468 (unused in this function) */
470 static int
471 init_one_plugin (void **slot, void * ARG_UNUSED (info))
473 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
474 bool ok = try_init_one_plugin (plugin);
475 if (!ok)
477 htab_remove_elt (plugin_name_args_tab, plugin->base_name);
478 XDELETE (plugin);
480 return 1;
483 #endif /* ENABLE_PLUGIN */
485 /* Main plugin initialization function. Called from compile_file() in
486 toplev.c. */
488 void
489 initialize_plugins (void)
491 /* If no plugin was specified in the command-line, simply return. */
492 if (!plugin_name_args_tab)
493 return;
495 timevar_push (TV_PLUGIN_INIT);
497 #ifdef ENABLE_PLUGIN
498 /* Traverse and initialize each plugin specified in the command-line. */
499 htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
500 #endif
502 timevar_pop (TV_PLUGIN_INIT);
505 /* Release memory used by one plugin. */
507 static int
508 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
510 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
511 XDELETE (plugin);
512 return 1;
515 /* Free memory allocated by the plugin system. */
517 void
518 finalize_plugins (void)
520 if (!plugin_name_args_tab)
521 return;
523 /* We can now delete the plugin_name_args object as it will no longer
524 be used. Note that base_name and argv fields (both of which were also
525 dynamically allocated) are not freed as they could still be used by
526 the plugin code. */
528 htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
530 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
531 htab_delete (plugin_name_args_tab);
532 plugin_name_args_tab = NULL;
535 /* Used to pass options to htab_traverse callbacks. */
537 struct print_options
539 FILE *file;
540 const char *indent;
543 /* Print the version of one plugin. */
545 static int
546 print_version_one_plugin (void **slot, void *data)
548 struct print_options *opt = (struct print_options *) data;
549 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
550 const char *version = plugin->version ? plugin->version : "Unknown version.";
552 fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
553 return 1;
556 /* Print the version of each plugin. */
558 void
559 print_plugins_versions (FILE *file, const char *indent)
561 struct print_options opt;
562 opt.file = file;
563 opt.indent = indent;
564 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
565 return;
567 fprintf (file, "%sVersions of loaded plugins:\n", indent);
568 htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
571 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
572 argument to htab_traverse_noresize. */
574 static int
575 print_help_one_plugin (void **slot, void *data)
577 struct print_options *opt = (struct print_options *) data;
578 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
579 const char *help = plugin->help ? plugin->help : "No help available .";
581 char *dup = xstrdup (help);
582 char *p, *nl;
583 fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
585 for (p = nl = dup; nl; p = nl)
587 nl = strchr (nl, '\n');
588 if (nl)
590 *nl = '\0';
591 nl++;
593 fprintf (opt->file, " %s %s\n", opt->indent, p);
596 free (dup);
597 return 1;
600 /* Print help for each plugin. The output goes to FILE and every line starts
601 with INDENT. */
603 void
604 print_plugins_help (FILE *file, const char *indent)
606 struct print_options opt;
607 opt.file = file;
608 opt.indent = indent;
609 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
610 return;
612 fprintf (file, "%sHelp for the loaded plugins:\n", indent);
613 htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
617 /* Return true if plugins have been loaded. */
619 bool
620 plugins_active_p (void)
622 int event;
624 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
625 if (plugin_callbacks[event])
626 return true;
628 return false;
632 /* Dump to FILE the names and associated events for all the active
633 plugins. */
635 void
636 dump_active_plugins (FILE *file)
638 int event;
640 if (!plugins_active_p ())
641 return;
643 fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
644 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
645 if (plugin_callbacks[event])
647 struct callback_info *ci;
649 fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]);
651 for (ci = plugin_callbacks[event]; ci; ci = ci->next)
652 fprintf (file, " %s", ci->plugin_name);
654 putc('\n', file);
659 /* Dump active plugins to stderr. */
661 void
662 debug_active_plugins (void)
664 dump_active_plugins (stderr);
667 /* The default version check. Compares every field in VERSION. */
669 bool
670 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
671 struct plugin_gcc_version *plugin_version)
673 if (!gcc_version || !plugin_version)
674 return false;
676 if (strcmp (gcc_version->basever, plugin_version->basever))
677 return false;
678 if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
679 return false;
680 if (strcmp (gcc_version->devphase, plugin_version->devphase))
681 return false;
682 if (strcmp (gcc_version->revision, plugin_version->revision))
683 return false;
684 if (strcmp (gcc_version->configuration_arguments,
685 plugin_version->configuration_arguments))
686 return false;
687 return true;