OSDN Git Service

2009-11-04 Richard Guenther <rguenther@suse.de>
[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_START_UNIT", 
62   "PLUGIN_EVENT_LAST"
63 };
64
65 /* Hash table for the plugin_name_args objects created during command-line
66    parsing.  */
67 static htab_t plugin_name_args_tab = NULL;
68
69 /* List node for keeping track of plugin-registered callback.  */
70 struct callback_info
71 {
72   const char *plugin_name;   /* Name of plugin that registers the callback.  */
73   plugin_callback_func func; /* Callback to be called.  */
74   void *user_data;           /* plugin-specified data.  */
75   struct callback_info *next;
76 };
77
78 /* An array of lists of 'callback_info' objects indexed by the event id.  */
79 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
80
81
82 #ifdef ENABLE_PLUGIN
83 /* Each plugin should define an initialization function with exactly
84    this name.  */
85 static const char *str_plugin_init_func_name = "plugin_init";
86
87 /* Each plugin should define this symbol to assert that it is
88    distributed under a GPL-compatible license.  */
89 static const char *str_license = "plugin_is_GPL_compatible";
90 #endif
91
92 /* Helper function for the hash table that compares the base_name of the
93    existing entry (S1) with the given string (S2).  */
94
95 static int
96 htab_str_eq (const void *s1, const void *s2)
97 {
98   const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
99   return !strcmp (plugin->base_name, (const char *) s2);
100 }
101
102
103 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
104    return NAME.  */
105
106 static char *
107 get_plugin_base_name (const char *full_name)
108 {
109   /* First get the base name part of the full-path name, i.e. NAME.so.  */
110   char *base_name = xstrdup (lbasename (full_name));
111
112   /* Then get rid of '.so' part of the name.  */
113   strip_off_ending (base_name, strlen (base_name));
114
115   return base_name;
116 }
117
118
119 /* Create a plugin_name_args object for the give plugin and insert it to
120    the hash table. This function is called when -fplugin=/path/to/NAME.so
121    option is processed.  */
122
123 void
124 add_new_plugin (const char* plugin_name)
125 {
126   struct plugin_name_args *plugin;
127   void **slot;
128   char *base_name = get_plugin_base_name (plugin_name);
129
130   /* If this is the first -fplugin= option we encounter, create 
131      'plugin_name_args_tab' hash table.  */
132   if (!plugin_name_args_tab)
133     plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
134                                         NULL);
135
136   slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
137
138   /* If the same plugin (name) has been specified earlier, either emit an
139      error or a warning message depending on if they have identical full
140      (path) names.  */
141   if (*slot)
142     {
143       plugin = (struct plugin_name_args *) *slot;
144       if (strcmp (plugin->full_name, plugin_name))
145         error ("Plugin %s was specified with different paths:\n%s\n%s",
146                plugin->base_name, plugin->full_name, plugin_name);
147       return;
148     }
149
150   plugin = XCNEW (struct plugin_name_args);
151   plugin->base_name = base_name;
152   plugin->full_name = plugin_name;
153
154   *slot = plugin;
155 }
156
157
158 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
159    'plugin_argument' object for the parsed key-value pair. ARG is
160    the <name>-<key>[=<value>] part of the option.  */
161
162 void
163 parse_plugin_arg_opt (const char *arg)
164 {
165   size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
166   const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
167   char *name, *key, *value;
168   void **slot;
169   bool name_parsed = false, key_parsed = false;
170
171   /* Iterate over the ARG string and identify the starting character position
172      of 'name', 'key', and 'value' and their lengths.  */
173   for (ptr = arg; *ptr; ++ptr)
174     {
175       /* Only the first '-' encountered is considered a separator between
176          'name' and 'key'. All the subsequent '-'s are considered part of
177          'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
178          the plugin name is 'foo' and the key is 'bar-primary-key'.  */
179       if (*ptr == '-' && !name_parsed)
180         {
181           name_len = len;
182           len = 0;
183           key_start = ptr + 1;
184           name_parsed = true;
185           continue;
186         }
187       else if (*ptr == '=')
188         {
189           if (key_parsed)
190             {
191               error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
192                      arg);
193               return;
194             }
195           key_len = len;
196           len = 0;
197           value_start = ptr + 1;
198           key_parsed = true;
199           continue;
200         }
201       else
202         ++len;
203     }
204
205   if (!key_start)
206     {
207       error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
208              arg);
209       return;
210     }
211
212   /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
213      Otherwise, it is the VALUE_LEN.  */
214   if (!value_start)
215     key_len = len;
216   else
217     value_len = len;
218
219   name = XNEWVEC (char, name_len + 1);
220   strncpy (name, name_start, name_len);
221   name[name_len] = '\0';
222
223   /* Check if the named plugin has already been specified earlier in the
224      command-line.  */
225   if (plugin_name_args_tab
226       && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
227           != NULL))
228     {
229       struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
230
231       key = XNEWVEC (char, key_len + 1);
232       strncpy (key, key_start, key_len);
233       key[key_len] = '\0';
234       if (value_start)
235         {
236           value = XNEWVEC (char, value_len + 1);
237           strncpy (value, value_start, value_len);
238           value[value_len] = '\0';
239         }
240       else
241         value = NULL;
242
243       /* Create a plugin_argument object for the parsed key-value pair.
244          If there are already arguments for this plugin, we will need to
245          adjust the argument array size by creating a new array and deleting
246          the old one. If the performance ever becomes an issue, we can
247          change the code by pre-allocating a larger array first.  */
248       if (plugin->argc > 0)
249         {
250           struct plugin_argument *args = XNEWVEC (struct plugin_argument,
251                                                   plugin->argc + 1);
252           memcpy (args, plugin->argv,
253                   sizeof (struct plugin_argument) * plugin->argc);
254           XDELETEVEC (plugin->argv);
255           plugin->argv = args;
256           ++plugin->argc;
257         }
258       else
259         {
260           gcc_assert (plugin->argv == NULL);
261           plugin->argv = XNEWVEC (struct plugin_argument, 1);
262           plugin->argc = 1;
263         }
264
265       plugin->argv[plugin->argc - 1].key = key;
266       plugin->argv[plugin->argc - 1].value = value;
267     }
268   else
269     error ("Plugin %s should be specified before -fplugin-arg-%s "
270            "in the command line", name, arg);
271
272   /* We don't need the plugin's name anymore. Just release it.  */
273   XDELETEVEC (name);
274 }
275
276 /* Register additional plugin information. NAME is the name passed to
277    plugin_init. INFO is the information that should be registered. */
278
279 static void
280 register_plugin_info (const char* name, struct plugin_info *info)
281 {
282   void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
283   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
284   plugin->version = info->version;
285   plugin->help = info->help;
286 }
287
288 /* Called from the plugin's initialization code. Register a single callback.
289    This function can be called multiple times.
290
291    PLUGIN_NAME - display name for this plugin
292    EVENT       - which event the callback is for
293    CALLBACK    - the callback to be called at the event
294    USER_DATA   - plugin-provided data   */
295
296 void
297 register_callback (const char *plugin_name,
298                    enum plugin_event event,
299                    plugin_callback_func callback,
300                    void *user_data)
301 {
302   switch (event)
303     {
304       case PLUGIN_PASS_MANAGER_SETUP:
305         gcc_assert (!callback);
306         register_pass ((struct register_pass_info *) user_data);
307         break;
308       case PLUGIN_INFO:
309         gcc_assert (!callback);
310         register_plugin_info (plugin_name, (struct plugin_info *) user_data);
311         break;
312       case PLUGIN_REGISTER_GGC_ROOTS:
313         gcc_assert (!callback);
314         ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
315         break;
316       case PLUGIN_REGISTER_GGC_CACHES:
317         gcc_assert (!callback);
318         ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data);
319         break;
320       case PLUGIN_FINISH_TYPE:
321       case PLUGIN_START_UNIT:
322       case PLUGIN_FINISH_UNIT:
323       case PLUGIN_CXX_CP_PRE_GENERICIZE:
324       case PLUGIN_GGC_START:
325       case PLUGIN_GGC_MARKING:
326       case PLUGIN_GGC_END:
327       case PLUGIN_ATTRIBUTES:
328       case PLUGIN_FINISH:
329         {
330           struct callback_info *new_callback;
331           if (!callback)
332             {
333               error ("Plugin %s registered a null callback function "
334                      "for event %s", plugin_name, plugin_event_name[event]);
335               return;
336             }
337           new_callback = XNEW (struct callback_info);
338           new_callback->plugin_name = plugin_name;
339           new_callback->func = callback;
340           new_callback->user_data = user_data;
341           new_callback->next = plugin_callbacks[event];
342           plugin_callbacks[event] = new_callback;
343         }
344         break;
345       case PLUGIN_EVENT_LAST:
346       default:
347         error ("Unkown callback event registered by plugin %s",
348                plugin_name);
349     }
350 }
351
352
353 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
354    the specified event.
355
356    EVENT    - the event identifier
357    GCC_DATA - event-specific data provided by the compiler  */
358
359 void
360 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
361 {
362   timevar_push (TV_PLUGIN_RUN);
363
364   switch (event)
365     {
366       case PLUGIN_FINISH_TYPE:
367       case PLUGIN_START_UNIT:
368       case PLUGIN_FINISH_UNIT:
369       case PLUGIN_CXX_CP_PRE_GENERICIZE:
370       case PLUGIN_ATTRIBUTES:
371       case PLUGIN_FINISH:
372       case PLUGIN_GGC_START:
373       case PLUGIN_GGC_MARKING:
374       case PLUGIN_GGC_END:
375         {
376           /* Iterate over every callback registered with this event and
377              call it.  */
378           struct callback_info *callback = plugin_callbacks[event];
379           for ( ; callback; callback = callback->next)
380             (*callback->func) (gcc_data, callback->user_data);
381         }
382         break;
383
384       case PLUGIN_PASS_MANAGER_SETUP:
385       case PLUGIN_EVENT_LAST:
386       case PLUGIN_REGISTER_GGC_ROOTS:
387       case PLUGIN_REGISTER_GGC_CACHES:
388       default:
389         gcc_assert (false);
390     }
391
392   timevar_pop (TV_PLUGIN_RUN);
393 }
394
395 #ifdef ENABLE_PLUGIN
396 /* We need a union to cast dlsym return value to a function pointer
397    as ISO C forbids assignment between function pointer and 'void *'.
398    Use explicit union instead of __extension__(<union_cast>) for
399    portability.  */
400 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
401 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
402 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
403
404 /* Try to initialize PLUGIN. Return true if successful. */
405
406 static bool
407 try_init_one_plugin (struct plugin_name_args *plugin)
408 {
409   void *dl_handle;
410   plugin_init_func plugin_init;
411   const char *err;
412   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
413
414   /* We use RTLD_NOW to accelerate binding and detect any mismatch
415      between the API expected by the plugin and the GCC API; we use
416      RTLD_GLOBAL which is useful to plugins which themselves call
417      dlopen.  */
418   dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
419   if (!dl_handle)
420     {
421       error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
422       return false;
423     }
424
425   /* Clear any existing error.  */
426   dlerror ();
427
428   /* Check the plugin license.  */
429   if (dlsym (dl_handle, str_license) == NULL)
430     fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
431                  "%s", plugin->full_name, dlerror ());
432
433   PTR_UNION_AS_VOID_PTR (plugin_init_union) =
434       dlsym (dl_handle, str_plugin_init_func_name);
435   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
436
437   if ((err = dlerror ()) != NULL)
438     {
439       error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
440              plugin->full_name, err);
441       return false;
442     }
443
444   /* Call the plugin-provided initialization routine with the arguments.  */
445   if ((*plugin_init) (plugin, &gcc_version))
446     {
447       error ("Fail to initialize plugin %s", plugin->full_name);
448       return false;
449     }
450
451   return true;
452 }
453
454
455 /* Routine to dlopen and initialize one plugin. This function is passed to
456    (and called by) the hash table traverse routine. Return 1 for the
457    htab_traverse to continue scan, 0 to stop.
458
459    SLOT - slot of the hash table element
460    INFO - auxiliary pointer handed to hash table traverse routine
461           (unused in this function)  */
462
463 static int
464 init_one_plugin (void **slot, void * ARG_UNUSED (info))
465 {
466   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
467   bool ok = try_init_one_plugin (plugin);
468   if (!ok)
469     {
470       htab_remove_elt (plugin_name_args_tab, plugin->base_name);
471       XDELETE (plugin);
472     }
473   return 1;
474 }
475
476 #endif  /* ENABLE_PLUGIN  */
477
478 /* Main plugin initialization function.  Called from compile_file() in
479    toplev.c.  */
480
481 void
482 initialize_plugins (void)
483 {
484   /* If no plugin was specified in the command-line, simply return.  */
485   if (!plugin_name_args_tab)
486     return;
487
488   timevar_push (TV_PLUGIN_INIT);
489  
490 #ifdef ENABLE_PLUGIN
491   /* Traverse and initialize each plugin specified in the command-line.  */
492   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
493 #endif
494
495   timevar_pop (TV_PLUGIN_INIT);
496 }
497
498 /* Release memory used by one plugin. */
499
500 static int
501 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
502 {
503   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
504   XDELETE (plugin);
505   return 1;
506 }
507
508 /* Free memory allocated by the plugin system. */
509
510 void
511 finalize_plugins (void)
512 {
513   if (!plugin_name_args_tab)
514     return;
515
516   /* We can now delete the plugin_name_args object as it will no longer
517      be used. Note that base_name and argv fields (both of which were also
518      dynamically allocated) are not freed as they could still be used by
519      the plugin code.  */
520
521   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
522
523   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
524   htab_delete (plugin_name_args_tab);
525   plugin_name_args_tab = NULL;
526 }
527
528 /* Used to pass options to htab_traverse callbacks. */
529
530 struct print_options
531 {
532   FILE *file;
533   const char *indent;
534 };
535
536 /* Print the version of one plugin. */
537
538 static int
539 print_version_one_plugin (void **slot, void *data)
540 {
541   struct print_options *opt = (struct print_options *) data;
542   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
543   const char *version = plugin->version ? plugin->version : "Unknown version.";
544
545   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
546   return 1;
547 }
548
549 /* Print the version of each plugin. */
550
551 void
552 print_plugins_versions (FILE *file, const char *indent)
553 {
554   struct print_options opt;
555   opt.file = file;
556   opt.indent = indent;
557   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
558     return;
559
560   fprintf (file, "%sVersions of loaded plugins:\n", indent);
561   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
562 }
563
564 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
565    argument to htab_traverse_noresize. */
566
567 static int
568 print_help_one_plugin (void **slot, void *data)
569 {
570   struct print_options *opt = (struct print_options *) data;
571   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
572   const char *help = plugin->help ? plugin->help : "No help available .";
573
574   char *dup = xstrdup (help);
575   char *p, *nl;
576   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
577
578   for (p = nl = dup; nl; p = nl)
579     {
580       nl = strchr (nl, '\n');
581       if (nl)
582         {
583           *nl = '\0';
584           nl++;
585         }
586       fprintf (opt->file, "   %s %s\n", opt->indent, p);
587     }
588
589   free (dup);
590   return 1;
591 }
592
593 /* Print help for each plugin. The output goes to FILE and every line starts
594    with INDENT. */
595
596 void
597 print_plugins_help (FILE *file, const char *indent)
598 {
599   struct print_options opt;
600   opt.file = file;
601   opt.indent = indent;
602   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
603     return;
604
605   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
606   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
607 }
608
609
610 /* Return true if plugins have been loaded.  */
611
612 bool
613 plugins_active_p (void)
614 {
615   int event;
616
617   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
618     if (plugin_callbacks[event])
619       return true;
620
621   return false;
622 }
623
624
625 /* Dump to FILE the names and associated events for all the active
626    plugins.  */
627
628 void
629 dump_active_plugins (FILE *file)
630 {
631   int event;
632
633   if (!plugins_active_p ())
634     return;
635
636   fprintf (stderr, "Event\t\t\tPlugins\n");
637   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
638     if (plugin_callbacks[event])
639       {
640         struct callback_info *ci;
641
642         fprintf (file, "%s\t", plugin_event_name[event]);
643
644         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
645           fprintf (file, "%s ", ci->plugin_name);
646
647         fprintf (file, "\n");
648       }
649 }
650
651
652 /* Dump active plugins to stderr.  */
653
654 void
655 debug_active_plugins (void)
656 {
657   dump_active_plugins (stderr);
658 }
659
660 /* The default version check. Compares every field in VERSION. */
661
662 bool
663 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
664                               struct plugin_gcc_version *plugin_version)
665 {
666   if (!gcc_version || !plugin_version)
667     return false;
668
669   if (strcmp (gcc_version->basever, plugin_version->basever))
670     return false;
671   if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
672     return false;
673   if (strcmp (gcc_version->devphase, plugin_version->devphase))
674     return false;
675   if (strcmp (gcc_version->revision, plugin_version->revision))
676     return false;
677   if (strcmp (gcc_version->configuration_arguments,
678               plugin_version->configuration_arguments))
679     return false;
680   return true;
681 }