OSDN Git Service

2009-11-19 Basile Starynkevitch <basile@starynkevitch.net>
[pf3gnuchains/gcc-fork.git] / gcc / plugin.c
1 /* Support for GCC plugin mechanism.
2    Copyright (C) 2009 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
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
33
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"
42
43 #ifdef ENABLE_PLUGIN
44 #include "plugin-version.h"
45 #endif
46
47 /* Event names as strings.  Keep in sync with enum plugin_event.  */
48 const char *plugin_event_name[] =
49 {
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"
65 };
66
67 /* A printf format large enough for the largest event above.  */
68 #define FMT_FOR_PLUGIN_EVENT "%-26s"
69
70 /* Hash table for the plugin_name_args objects created during command-line
71    parsing.  */
72 static htab_t plugin_name_args_tab = NULL;
73
74 /* List node for keeping track of plugin-registered callback.  */
75 struct callback_info
76 {
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;
81 };
82
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 };
85
86
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";
91
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
96
97 /* Helper function for the hash table that compares the base_name of the
98    existing entry (S1) with the given string (S2).  */
99
100 static int
101 htab_str_eq (const void *s1, const void *s2)
102 {
103   const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
104   return !strcmp (plugin->base_name, (const char *) s2);
105 }
106
107
108 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
109    return NAME.  */
110
111 static char *
112 get_plugin_base_name (const char *full_name)
113 {
114   /* First get the base name part of the full-path name, i.e. NAME.so.  */
115   char *base_name = xstrdup (lbasename (full_name));
116
117   /* Then get rid of '.so' part of the name.  */
118   strip_off_ending (base_name, strlen (base_name));
119
120   return base_name;
121 }
122
123
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.  */
127
128 void
129 add_new_plugin (const char* plugin_name)
130 {
131   struct plugin_name_args *plugin;
132   void **slot;
133   char *base_name = get_plugin_base_name (plugin_name);
134
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);
140
141   slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
142
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)
147     {
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;
153     }
154
155   plugin = XCNEW (struct plugin_name_args);
156   plugin->base_name = base_name;
157   plugin->full_name = plugin_name;
158
159   *slot = plugin;
160 }
161
162
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.  */
166
167 void
168 parse_plugin_arg_opt (const char *arg)
169 {
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;
175
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)
179     {
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)
185         {
186           name_len = len;
187           len = 0;
188           key_start = ptr + 1;
189           name_parsed = true;
190           continue;
191         }
192       else if (*ptr == '=')
193         {
194           if (key_parsed)
195             {
196               error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
197                      arg);
198               return;
199             }
200           key_len = len;
201           len = 0;
202           value_start = ptr + 1;
203           key_parsed = true;
204           continue;
205         }
206       else
207         ++len;
208     }
209
210   if (!key_start)
211     {
212       error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
213              arg);
214       return;
215     }
216
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;
223
224   name = XNEWVEC (char, name_len + 1);
225   strncpy (name, name_start, name_len);
226   name[name_len] = '\0';
227
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))
233     {
234       struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
235
236       key = XNEWVEC (char, key_len + 1);
237       strncpy (key, key_start, key_len);
238       key[key_len] = '\0';
239       if (value_start)
240         {
241           value = XNEWVEC (char, value_len + 1);
242           strncpy (value, value_start, value_len);
243           value[value_len] = '\0';
244         }
245       else
246         value = NULL;
247
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)
254         {
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;
262         }
263       else
264         {
265           gcc_assert (plugin->argv == NULL);
266           plugin->argv = XNEWVEC (struct plugin_argument, 1);
267           plugin->argc = 1;
268         }
269
270       plugin->argv[plugin->argc - 1].key = key;
271       plugin->argv[plugin->argc - 1].value = value;
272     }
273   else
274     error ("Plugin %s should be specified before -fplugin-arg-%s "
275            "in the command line", name, arg);
276
277   /* We don't need the plugin's name anymore. Just release it.  */
278   XDELETEVEC (name);
279 }
280
281 /* Register additional plugin information. NAME is the name passed to
282    plugin_init. INFO is the information that should be registered. */
283
284 static void
285 register_plugin_info (const char* name, struct plugin_info *info)
286 {
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;
291 }
292
293 /* Called from the plugin's initialization code. Register a single callback.
294    This function can be called multiple times.
295
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   */
300
301 void
302 register_callback (const char *plugin_name,
303                    enum plugin_event event,
304                    plugin_callback_func callback,
305                    void *user_data)
306 {
307   switch (event)
308     {
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:
335         {
336           struct callback_info *new_callback;
337           if (!callback)
338             {
339               error ("Plugin %s registered a null callback function "
340                      "for event %s", plugin_name, plugin_event_name[event]);
341               return;
342             }
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;
349         }
350         break;
351       case PLUGIN_EVENT_LAST:
352       default:
353         error ("Unknown callback event registered by plugin %s",
354                plugin_name);
355     }
356 }
357
358
359 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
360    the specified event.
361
362    EVENT    - the event identifier
363    GCC_DATA - event-specific data provided by the compiler  */
364
365 void
366 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
367 {
368   timevar_push (TV_PLUGIN_RUN);
369
370   switch (event)
371     {
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:
382         {
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);
388         }
389         break;
390
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);
397     }
398
399   timevar_pop (TV_PLUGIN_RUN);
400 }
401
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)
410
411 /* Try to initialize PLUGIN. Return true if successful. */
412
413 static bool
414 try_init_one_plugin (struct plugin_name_args *plugin)
415 {
416   void *dl_handle;
417   plugin_init_func plugin_init;
418   const char *err;
419   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
420
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)
427     {
428       error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
429       return false;
430     }
431
432   /* Clear any existing error.  */
433   dlerror ();
434
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 ());
439
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);
443
444   if ((err = dlerror ()) != NULL)
445     {
446       error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
447              plugin->full_name, err);
448       return false;
449     }
450
451   /* Call the plugin-provided initialization routine with the arguments.  */
452   if ((*plugin_init) (plugin, &gcc_version))
453     {
454       error ("Fail to initialize plugin %s", plugin->full_name);
455       return false;
456     }
457
458   return true;
459 }
460
461
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.
465
466    SLOT - slot of the hash table element
467    INFO - auxiliary pointer handed to hash table traverse routine
468           (unused in this function)  */
469
470 static int
471 init_one_plugin (void **slot, void * ARG_UNUSED (info))
472 {
473   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
474   bool ok = try_init_one_plugin (plugin);
475   if (!ok)
476     {
477       htab_remove_elt (plugin_name_args_tab, plugin->base_name);
478       XDELETE (plugin);
479     }
480   return 1;
481 }
482
483 #endif  /* ENABLE_PLUGIN  */
484
485 /* Main plugin initialization function.  Called from compile_file() in
486    toplev.c.  */
487
488 void
489 initialize_plugins (void)
490 {
491   /* If no plugin was specified in the command-line, simply return.  */
492   if (!plugin_name_args_tab)
493     return;
494
495   timevar_push (TV_PLUGIN_INIT);
496  
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
501
502   timevar_pop (TV_PLUGIN_INIT);
503 }
504
505 /* Release memory used by one plugin. */
506
507 static int
508 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
509 {
510   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
511   XDELETE (plugin);
512   return 1;
513 }
514
515 /* Free memory allocated by the plugin system. */
516
517 void
518 finalize_plugins (void)
519 {
520   if (!plugin_name_args_tab)
521     return;
522
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.  */
527
528   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
529
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;
533 }
534
535 /* Used to pass options to htab_traverse callbacks. */
536
537 struct print_options
538 {
539   FILE *file;
540   const char *indent;
541 };
542
543 /* Print the version of one plugin. */
544
545 static int
546 print_version_one_plugin (void **slot, void *data)
547 {
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.";
551
552   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
553   return 1;
554 }
555
556 /* Print the version of each plugin. */
557
558 void
559 print_plugins_versions (FILE *file, const char *indent)
560 {
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;
566
567   fprintf (file, "%sVersions of loaded plugins:\n", indent);
568   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
569 }
570
571 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
572    argument to htab_traverse_noresize. */
573
574 static int
575 print_help_one_plugin (void **slot, void *data)
576 {
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 .";
580
581   char *dup = xstrdup (help);
582   char *p, *nl;
583   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
584
585   for (p = nl = dup; nl; p = nl)
586     {
587       nl = strchr (nl, '\n');
588       if (nl)
589         {
590           *nl = '\0';
591           nl++;
592         }
593       fprintf (opt->file, "   %s %s\n", opt->indent, p);
594     }
595
596   free (dup);
597   return 1;
598 }
599
600 /* Print help for each plugin. The output goes to FILE and every line starts
601    with INDENT. */
602
603 void
604 print_plugins_help (FILE *file, const char *indent)
605 {
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;
611
612   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
613   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
614 }
615
616
617 /* Return true if plugins have been loaded.  */
618
619 bool
620 plugins_active_p (void)
621 {
622   int event;
623
624   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
625     if (plugin_callbacks[event])
626       return true;
627
628   return false;
629 }
630
631
632 /* Dump to FILE the names and associated events for all the active
633    plugins.  */
634
635 void
636 dump_active_plugins (FILE *file)
637 {
638   int event;
639
640   if (!plugins_active_p ())
641     return;
642
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])
646       {
647         struct callback_info *ci;
648
649         fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]);
650
651         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
652           fprintf (file, " %s", ci->plugin_name);
653
654         putc('\n', file);
655       }
656 }
657
658
659 /* Dump active plugins to stderr.  */
660
661 void
662 debug_active_plugins (void)
663 {
664   dump_active_plugins (stderr);
665 }
666
667 /* The default version check. Compares every field in VERSION. */
668
669 bool
670 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
671                               struct plugin_gcc_version *plugin_version)
672 {
673   if (!gcc_version || !plugin_version)
674     return false;
675
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;
688 }