plugins.texi: Document plugin_is_GPL_compatible.
[gcc.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_EVENT_LAST"
61 };
62
63 /* Hash table for the plugin_name_args objects created during command-line
64 parsing. */
65 static htab_t plugin_name_args_tab = NULL;
66
67 /* List node for keeping track of plugin-registered callback. */
68 struct callback_info
69 {
70 const char *plugin_name; /* Name of plugin that registers the callback. */
71 plugin_callback_func func; /* Callback to be called. */
72 void *user_data; /* plugin-specified data. */
73 struct callback_info *next;
74 };
75
76 /* An array of lists of 'callback_info' objects indexed by the event id. */
77 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
78
79 /* List node for an inserted pass instance. We need to keep track of all
80 the newly-added pass instances (with 'added_pass_nodes' defined below)
81 so that we can register their dump files after pass-positioning is finished.
82 Registering dumping files needs to be post-processed or the
83 static_pass_number of the opt_pass object would be modified and mess up
84 the dump file names of future pass instances to be added. */
85 struct pass_list_node
86 {
87 struct opt_pass *pass;
88 struct pass_list_node *next;
89 };
90
91 static struct pass_list_node *added_pass_nodes = NULL;
92 static struct pass_list_node *prev_added_pass_node;
93
94 #ifdef ENABLE_PLUGIN
95 /* Each plugin should define an initialization function with exactly
96 this name. */
97 static const char *str_plugin_init_func_name = "plugin_init";
98
99 /* Each plugin should define this symbol to assert that it is
100 distributed under a GPL-compatible license. */
101 static const char *str_license = "plugin_is_GPL_compatible";
102 #endif
103
104 /* Helper function for the hash table that compares the base_name of the
105 existing entry (S1) with the given string (S2). */
106
107 static int
108 htab_str_eq (const void *s1, const void *s2)
109 {
110 const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
111 return !strcmp (plugin->base_name, (const char *) s2);
112 }
113
114
115 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
116 return NAME. */
117
118 static char *
119 get_plugin_base_name (const char *full_name)
120 {
121 /* First get the base name part of the full-path name, i.e. NAME.so. */
122 char *base_name = xstrdup (lbasename (full_name));
123
124 /* Then get rid of '.so' part of the name. */
125 strip_off_ending (base_name, strlen (base_name));
126
127 return base_name;
128 }
129
130
131 /* Create a plugin_name_args object for the give plugin and insert it to
132 the hash table. This function is called when -fplugin=/path/to/NAME.so
133 option is processed. */
134
135 void
136 add_new_plugin (const char* plugin_name)
137 {
138 struct plugin_name_args *plugin;
139 void **slot;
140 char *base_name = get_plugin_base_name (plugin_name);
141
142 /* If this is the first -fplugin= option we encounter, create
143 'plugin_name_args_tab' hash table. */
144 if (!plugin_name_args_tab)
145 plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
146 NULL);
147
148 slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
149
150 /* If the same plugin (name) has been specified earlier, either emit an
151 error or a warning message depending on if they have identical full
152 (path) names. */
153 if (*slot)
154 {
155 plugin = (struct plugin_name_args *) *slot;
156 if (strcmp (plugin->full_name, plugin_name))
157 error ("Plugin %s was specified with different paths:\n%s\n%s",
158 plugin->base_name, plugin->full_name, plugin_name);
159 return;
160 }
161
162 plugin = XCNEW (struct plugin_name_args);
163 plugin->base_name = base_name;
164 plugin->full_name = plugin_name;
165
166 *slot = plugin;
167 }
168
169
170 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
171 'plugin_argument' object for the parsed key-value pair. ARG is
172 the <name>-<key>[=<value>] part of the option. */
173
174 void
175 parse_plugin_arg_opt (const char *arg)
176 {
177 size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
178 const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
179 char *name, *key, *value;
180 void **slot;
181 bool name_parsed = false, key_parsed = false;
182
183 /* Iterate over the ARG string and identify the starting character position
184 of 'name', 'key', and 'value' and their lengths. */
185 for (ptr = arg; *ptr; ++ptr)
186 {
187 /* Only the first '-' encountered is considered a separator between
188 'name' and 'key'. All the subsequent '-'s are considered part of
189 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
190 the plugin name is 'foo' and the key is 'bar-primary-key'. */
191 if (*ptr == '-' && !name_parsed)
192 {
193 name_len = len;
194 len = 0;
195 key_start = ptr + 1;
196 name_parsed = true;
197 continue;
198 }
199 else if (*ptr == '=')
200 {
201 if (key_parsed)
202 {
203 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
204 arg);
205 return;
206 }
207 key_len = len;
208 len = 0;
209 value_start = ptr + 1;
210 key_parsed = true;
211 continue;
212 }
213 else
214 ++len;
215 }
216
217 if (!key_start)
218 {
219 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
220 arg);
221 return;
222 }
223
224 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
225 Otherwise, it is the VALUE_LEN. */
226 if (!value_start)
227 key_len = len;
228 else
229 value_len = len;
230
231 name = XNEWVEC (char, name_len + 1);
232 strncpy (name, name_start, name_len);
233 name[name_len] = '\0';
234
235 /* Check if the named plugin has already been specified earlier in the
236 command-line. */
237 if (plugin_name_args_tab
238 && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
239 != NULL))
240 {
241 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
242
243 key = XNEWVEC (char, key_len + 1);
244 strncpy (key, key_start, key_len);
245 key[key_len] = '\0';
246 if (value_start)
247 {
248 value = XNEWVEC (char, value_len + 1);
249 strncpy (value, value_start, value_len);
250 value[value_len] = '\0';
251 }
252 else
253 value = NULL;
254
255 /* Create a plugin_argument object for the parsed key-value pair.
256 If there are already arguments for this plugin, we will need to
257 adjust the argument array size by creating a new array and deleting
258 the old one. If the performance ever becomes an issue, we can
259 change the code by pre-allocating a larger array first. */
260 if (plugin->argc > 0)
261 {
262 struct plugin_argument *args = XNEWVEC (struct plugin_argument,
263 plugin->argc + 1);
264 memcpy (args, plugin->argv,
265 sizeof (struct plugin_argument) * plugin->argc);
266 XDELETEVEC (plugin->argv);
267 plugin->argv = args;
268 ++plugin->argc;
269 }
270 else
271 {
272 gcc_assert (plugin->argv == NULL);
273 plugin->argv = XNEWVEC (struct plugin_argument, 1);
274 plugin->argc = 1;
275 }
276
277 plugin->argv[plugin->argc - 1].key = key;
278 plugin->argv[plugin->argc - 1].value = value;
279 }
280 else
281 error ("Plugin %s should be specified before -fplugin-arg-%s "
282 "in the command line", name, arg);
283
284 /* We don't need the plugin's name anymore. Just release it. */
285 XDELETEVEC (name);
286 }
287
288
289 /* Insert the plugin pass at the proper position. Return true if the pass
290 is successfully added.
291
292 PLUGIN_PASS_INFO - new pass to be inserted
293 PASS_LIST - root of the pass list to insert the new pass to */
294
295 static bool
296 position_pass (struct plugin_pass *plugin_pass_info,
297 struct opt_pass **pass_list)
298 {
299 struct opt_pass *pass = *pass_list, *prev_pass = NULL;
300 bool success = false;
301
302 for ( ; pass; prev_pass = pass, pass = pass->next)
303 {
304 /* Check if the current pass is of the same type as the new pass and
305 matches the name and the instance number of the reference pass. */
306 if (pass->type == plugin_pass_info->pass->type
307 && pass->name
308 && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
309 && ((plugin_pass_info->ref_pass_instance_number == 0)
310 || (plugin_pass_info->ref_pass_instance_number ==
311 pass->static_pass_number)
312 || (plugin_pass_info->ref_pass_instance_number == 1
313 && pass->todo_flags_start & TODO_mark_first_instance)))
314 {
315 struct opt_pass *new_pass = plugin_pass_info->pass;
316 struct pass_list_node *new_pass_node;
317
318 /* The following code (if-statement) is adopted from next_pass_1. */
319 if (new_pass->static_pass_number)
320 {
321 new_pass = XNEW (struct opt_pass);
322 memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
323 new_pass->next = NULL;
324
325 new_pass->todo_flags_start &= ~TODO_mark_first_instance;
326
327 plugin_pass_info->pass->static_pass_number -= 1;
328 new_pass->static_pass_number =
329 -plugin_pass_info->pass->static_pass_number;
330 }
331 else
332 {
333 new_pass->todo_flags_start |= TODO_mark_first_instance;
334 new_pass->static_pass_number = -1;
335 }
336
337 /* Insert the new pass instance based on the positioning op. */
338 switch (plugin_pass_info->pos_op)
339 {
340 case PASS_POS_INSERT_AFTER:
341 new_pass->next = pass->next;
342 pass->next = new_pass;
343
344 /* Skip newly inserted pass to avoid repeated
345 insertions in the case where the new pass and the
346 existing one have the same name. */
347 pass = new_pass;
348 break;
349 case PASS_POS_INSERT_BEFORE:
350 new_pass->next = pass;
351 if (prev_pass)
352 prev_pass->next = new_pass;
353 else
354 *pass_list = new_pass;
355 break;
356 case PASS_POS_REPLACE:
357 new_pass->next = pass->next;
358 if (prev_pass)
359 prev_pass->next = new_pass;
360 else
361 *pass_list = new_pass;
362 new_pass->sub = pass->sub;
363 new_pass->tv_id = pass->tv_id;
364 pass = new_pass;
365 break;
366 default:
367 error ("Invalid pass positioning operation");
368 return false;
369 }
370
371 /* Save the newly added pass (instance) in the added_pass_nodes
372 list so that we can register its dump file later. Note that
373 we cannot register the dump file now because doing so will modify
374 the static_pass_number of the opt_pass object and therefore
375 mess up the dump file name of future instances. */
376 new_pass_node = XCNEW (struct pass_list_node);
377 new_pass_node->pass = new_pass;
378 if (!added_pass_nodes)
379 added_pass_nodes = new_pass_node;
380 else
381 prev_added_pass_node->next = new_pass_node;
382 prev_added_pass_node = new_pass_node;
383
384 success = true;
385 }
386
387 if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
388 success = true;
389 }
390
391 return success;
392 }
393
394
395 /* Hook into the pass lists (trees) a new pass registered by a plugin.
396
397 PLUGIN_NAME - display name for the plugin
398 PASS_INFO - plugin pass information that specifies the opt_pass object,
399 reference pass, instance number, and how to position
400 the pass */
401
402 static void
403 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
404 {
405 if (!pass_info->pass)
406 {
407 error ("No pass specified when registering a new pass in plugin %s",
408 plugin_name);
409 return;
410 }
411
412 if (!pass_info->reference_pass_name)
413 {
414 error ("No reference pass specified for positioning the pass "
415 " from plugin %s", plugin_name);
416 return;
417 }
418
419 /* Try to insert the new pass to the pass lists. We need to check all
420 three lists as the reference pass could be in one (or all) of them. */
421 if (!position_pass (pass_info, &all_lowering_passes)
422 && !position_pass (pass_info, &all_ipa_passes)
423 && !position_pass (pass_info, &all_passes))
424 error ("Failed to position pass %s registered by plugin %s. "
425 "Cannot find the (specified instance of) reference pass %s",
426 pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
427 else
428 {
429 /* OK, we have successfully inserted the new pass. We need to register
430 the dump files for the newly added pass and its duplicates (if any).
431 Because the registration of plugin passes happens after the
432 command-line options are parsed, the options that specify single
433 pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
434 plugin passes. Therefore we currently can only enable dumping of
435 new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
436 are specified. While doing so, we also delete the pass_list_node
437 objects created during pass positioning. */
438 while (added_pass_nodes)
439 {
440 struct pass_list_node *next_node = added_pass_nodes->next;
441 enum tree_dump_index tdi;
442 register_one_dump_file (added_pass_nodes->pass);
443 if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
444 || added_pass_nodes->pass->type == IPA_PASS)
445 tdi = TDI_ipa_all;
446 else if (added_pass_nodes->pass->type == GIMPLE_PASS)
447 tdi = TDI_tree_all;
448 else
449 tdi = TDI_rtl_all;
450 /* Check if dump-all flag is specified. */
451 if (get_dump_file_info (tdi)->state)
452 get_dump_file_info (added_pass_nodes->pass->static_pass_number)
453 ->state = get_dump_file_info (tdi)->state;
454 XDELETE (added_pass_nodes);
455 added_pass_nodes = next_node;
456 }
457 }
458 }
459
460
461 /* Register additional plugin information. NAME is the name passed to
462 plugin_init. INFO is the information that should be registered. */
463
464 static void
465 register_plugin_info (const char* name, struct plugin_info *info)
466 {
467 void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
468 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
469 plugin->version = info->version;
470 plugin->help = info->help;
471 }
472
473 /* Called from the plugin's initialization code. Register a single callback.
474 This function can be called multiple times.
475
476 PLUGIN_NAME - display name for this plugin
477 EVENT - which event the callback is for
478 CALLBACK - the callback to be called at the event
479 USER_DATA - plugin-provided data */
480
481 void
482 register_callback (const char *plugin_name,
483 enum plugin_event event,
484 plugin_callback_func callback,
485 void *user_data)
486 {
487 switch (event)
488 {
489 case PLUGIN_PASS_MANAGER_SETUP:
490 gcc_assert (!callback);
491 register_pass (plugin_name, (struct plugin_pass *) user_data);
492 break;
493 case PLUGIN_INFO:
494 gcc_assert (!callback);
495 register_plugin_info (plugin_name, (struct plugin_info *) user_data);
496 break;
497 case PLUGIN_REGISTER_GGC_ROOTS:
498 gcc_assert (!callback);
499 ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
500 break;
501 case PLUGIN_FINISH_TYPE:
502 case PLUGIN_FINISH_UNIT:
503 case PLUGIN_CXX_CP_PRE_GENERICIZE:
504 case PLUGIN_GGC_START:
505 case PLUGIN_GGC_MARKING:
506 case PLUGIN_GGC_END:
507 case PLUGIN_ATTRIBUTES:
508 case PLUGIN_FINISH:
509 {
510 struct callback_info *new_callback;
511 if (!callback)
512 {
513 error ("Plugin %s registered a null callback function "
514 "for event %s", plugin_name, plugin_event_name[event]);
515 return;
516 }
517 new_callback = XNEW (struct callback_info);
518 new_callback->plugin_name = plugin_name;
519 new_callback->func = callback;
520 new_callback->user_data = user_data;
521 new_callback->next = plugin_callbacks[event];
522 plugin_callbacks[event] = new_callback;
523 }
524 break;
525 case PLUGIN_EVENT_LAST:
526 default:
527 error ("Unkown callback event registered by plugin %s",
528 plugin_name);
529 }
530 }
531
532
533 /* Called from inside GCC. Invoke all plug-in callbacks registered with
534 the specified event.
535
536 EVENT - the event identifier
537 GCC_DATA - event-specific data provided by the compiler */
538
539 void
540 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
541 {
542 timevar_push (TV_PLUGIN_RUN);
543
544 switch (event)
545 {
546 case PLUGIN_FINISH_TYPE:
547 case PLUGIN_FINISH_UNIT:
548 case PLUGIN_CXX_CP_PRE_GENERICIZE:
549 case PLUGIN_ATTRIBUTES:
550 case PLUGIN_FINISH:
551 case PLUGIN_GGC_START:
552 case PLUGIN_GGC_MARKING:
553 case PLUGIN_GGC_END:
554 {
555 /* Iterate over every callback registered with this event and
556 call it. */
557 struct callback_info *callback = plugin_callbacks[event];
558 for ( ; callback; callback = callback->next)
559 (*callback->func) (gcc_data, callback->user_data);
560 }
561 break;
562
563 case PLUGIN_PASS_MANAGER_SETUP:
564 case PLUGIN_EVENT_LAST:
565 case PLUGIN_REGISTER_GGC_ROOTS:
566 default:
567 gcc_assert (false);
568 }
569
570 timevar_pop (TV_PLUGIN_RUN);
571 }
572
573 #ifdef ENABLE_PLUGIN
574 /* We need a union to cast dlsym return value to a function pointer
575 as ISO C forbids assignment between function pointer and 'void *'.
576 Use explicit union instead of __extension__(<union_cast>) for
577 portability. */
578 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
579 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
580 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
581
582 /* Try to initialize PLUGIN. Return true if successful. */
583
584 static bool
585 try_init_one_plugin (struct plugin_name_args *plugin)
586 {
587 void *dl_handle;
588 plugin_init_func plugin_init;
589 char *err;
590 PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
591
592 dl_handle = dlopen (plugin->full_name, RTLD_NOW);
593 if (!dl_handle)
594 {
595 error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
596 return false;
597 }
598
599 /* Clear any existing error. */
600 dlerror ();
601
602 /* Check the plugin license. */
603 if (dlsym (dl_handle, str_license) == NULL)
604 fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
605 "%s", plugin->full_name, dlerror ());
606
607 PTR_UNION_AS_VOID_PTR (plugin_init_union) =
608 dlsym (dl_handle, str_plugin_init_func_name);
609 plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
610
611 if ((err = dlerror ()) != NULL)
612 {
613 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
614 plugin->full_name, err);
615 return false;
616 }
617
618 /* Call the plugin-provided initialization routine with the arguments. */
619 if ((*plugin_init) (plugin, &gcc_version))
620 {
621 error ("Fail to initialize plugin %s", plugin->full_name);
622 return false;
623 }
624
625 return true;
626 }
627
628
629 /* Routine to dlopen and initialize one plugin. This function is passed to
630 (and called by) the hash table traverse routine. Return 1 for the
631 htab_traverse to continue scan, 0 to stop.
632
633 SLOT - slot of the hash table element
634 INFO - auxiliary pointer handed to hash table traverse routine
635 (unused in this function) */
636
637 static int
638 init_one_plugin (void **slot, void * ARG_UNUSED (info))
639 {
640 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
641 bool ok = try_init_one_plugin (plugin);
642 if (!ok)
643 {
644 htab_remove_elt (plugin_name_args_tab, plugin->base_name);
645 XDELETE (plugin);
646 }
647 return 1;
648 }
649
650 #endif /* ENABLE_PLUGIN */
651
652 /* Main plugin initialization function. Called from compile_file() in
653 toplev.c. */
654
655 void
656 initialize_plugins (void)
657 {
658 /* If no plugin was specified in the command-line, simply return. */
659 if (!plugin_name_args_tab)
660 return;
661
662 timevar_push (TV_PLUGIN_INIT);
663
664 #ifdef ENABLE_PLUGIN
665 /* Traverse and initialize each plugin specified in the command-line. */
666 htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
667 #endif
668
669 timevar_pop (TV_PLUGIN_INIT);
670 }
671
672 /* Release memory used by one plugin. */
673
674 static int
675 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
676 {
677 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
678 XDELETE (plugin);
679 return 1;
680 }
681
682 /* Free memory allocated by the plugin system. */
683
684 void
685 finalize_plugins (void)
686 {
687 if (!plugin_name_args_tab)
688 return;
689
690 /* We can now delete the plugin_name_args object as it will no longer
691 be used. Note that base_name and argv fields (both of which were also
692 dynamically allocated) are not freed as they could still be used by
693 the plugin code. */
694
695 htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
696
697 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
698 htab_delete (plugin_name_args_tab);
699 plugin_name_args_tab = NULL;
700 }
701
702 /* Used to pass options to htab_traverse callbacks. */
703
704 struct print_options
705 {
706 FILE *file;
707 const char *indent;
708 };
709
710 /* Print the version of one plugin. */
711
712 static int
713 print_version_one_plugin (void **slot, void *data)
714 {
715 struct print_options *opt = (struct print_options *) data;
716 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
717 const char *version = plugin->version ? plugin->version : "Unknown version.";
718
719 fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
720 return 1;
721 }
722
723 /* Print the version of each plugin. */
724
725 void
726 print_plugins_versions (FILE *file, const char *indent)
727 {
728 struct print_options opt;
729 opt.file = file;
730 opt.indent = indent;
731 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
732 return;
733
734 fprintf (file, "%sVersions of loaded plugins:\n", indent);
735 htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
736 }
737
738 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
739 argument to htab_traverse_noresize. */
740
741 static int
742 print_help_one_plugin (void **slot, void *data)
743 {
744 struct print_options *opt = (struct print_options *) data;
745 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
746 const char *help = plugin->help ? plugin->help : "No help available .";
747
748 char *dup = xstrdup (help);
749 char *p, *nl;
750 fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
751
752 for (p = nl = dup; nl; p = nl)
753 {
754 nl = strchr (nl, '\n');
755 if (nl)
756 {
757 *nl = '\0';
758 nl++;
759 }
760 fprintf (opt->file, " %s %s\n", opt->indent, p);
761 }
762
763 free (dup);
764 return 1;
765 }
766
767 /* Print help for each plugin. The output goes to FILE and every line starts
768 with INDENT. */
769
770 void
771 print_plugins_help (FILE *file, const char *indent)
772 {
773 struct print_options opt;
774 opt.file = file;
775 opt.indent = indent;
776 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
777 return;
778
779 fprintf (file, "%sHelp for the loaded plugins:\n", indent);
780 htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
781 }
782
783
784 /* Return true if plugins have been loaded. */
785
786 bool
787 plugins_active_p (void)
788 {
789 int event;
790
791 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
792 if (plugin_callbacks[event])
793 return true;
794
795 return false;
796 }
797
798
799 /* Dump to FILE the names and associated events for all the active
800 plugins. */
801
802 void
803 dump_active_plugins (FILE *file)
804 {
805 int event;
806
807 if (!plugins_active_p ())
808 return;
809
810 fprintf (stderr, "Event\t\t\tPlugins\n");
811 for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
812 if (plugin_callbacks[event])
813 {
814 struct callback_info *ci;
815
816 fprintf (file, "%s\t", plugin_event_name[event]);
817
818 for (ci = plugin_callbacks[event]; ci; ci = ci->next)
819 fprintf (file, "%s ", ci->plugin_name);
820
821 fprintf (file, "\n");
822 }
823 }
824
825
826 /* Dump active plugins to stderr. */
827
828 void
829 debug_active_plugins (void)
830 {
831 dump_active_plugins (stderr);
832 }
833
834 /* The default version check. Compares every field in VERSION. */
835
836 bool
837 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
838 struct plugin_gcc_version *plugin_version)
839 {
840 if (!gcc_version || !plugin_version)
841 return false;
842
843 if (strcmp (gcc_version->basever, plugin_version->basever))
844 return false;
845 if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
846 return false;
847 if (strcmp (gcc_version->devphase, plugin_version->devphase))
848 return false;
849 if (strcmp (gcc_version->revision, plugin_version->revision))
850 return false;
851 if (strcmp (gcc_version->configuration_arguments,
852 plugin_version->configuration_arguments))
853 return false;
854 return true;
855 }