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