1 /* Support for GCC plugin mechanism.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* This file contains the support for GCC plugin mechanism based on the
21 APIs described in doc/plugin.texi. */
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
34 #include "coretypes.h"
37 #include "tree-pass.h"
44 #include "plugin-version.h"
47 /* Event names as strings. Keep in sync with enum plugin_event. */
48 const char *plugin_event_name
[] =
50 "PLUGIN_PASS_MANAGER_SETUP",
53 "PLUGIN_CXX_CP_PRE_GENERICIZE",
59 "PLUGIN_REGISTER_GGC_ROOTS",
60 "PLUGIN_REGISTER_GGC_CACHES",
65 /* Hash table for the plugin_name_args objects created during command-line
67 static htab_t plugin_name_args_tab
= NULL
;
69 /* List node for keeping track of plugin-registered callback. */
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
;
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
};
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. */
89 struct opt_pass
*pass
;
90 struct pass_list_node
*next
;
93 static struct pass_list_node
*added_pass_nodes
= NULL
;
94 static struct pass_list_node
*prev_added_pass_node
;
97 /* Each plugin should define an initialization function with exactly
99 static const char *str_plugin_init_func_name
= "plugin_init";
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";
106 /* Helper function for the hash table that compares the base_name of the
107 existing entry (S1) with the given string (S2). */
110 htab_str_eq (const void *s1
, const void *s2
)
112 const struct plugin_name_args
*plugin
= (const struct plugin_name_args
*) s1
;
113 return !strcmp (plugin
->base_name
, (const char *) s2
);
117 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
121 get_plugin_base_name (const char *full_name
)
123 /* First get the base name part of the full-path name, i.e. NAME.so. */
124 char *base_name
= xstrdup (lbasename (full_name
));
126 /* Then get rid of '.so' part of the name. */
127 strip_off_ending (base_name
, strlen (base_name
));
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. */
138 add_new_plugin (const char* plugin_name
)
140 struct plugin_name_args
*plugin
;
142 char *base_name
= get_plugin_base_name (plugin_name
);
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
,
150 slot
= htab_find_slot (plugin_name_args_tab
, base_name
, INSERT
);
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
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
);
164 plugin
= XCNEW (struct plugin_name_args
);
165 plugin
->base_name
= base_name
;
166 plugin
->full_name
= plugin_name
;
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. */
177 parse_plugin_arg_opt (const char *arg
)
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
;
183 bool name_parsed
= false, key_parsed
= false;
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
)
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
)
201 else if (*ptr
== '=')
205 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
211 value_start
= ptr
+ 1;
221 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
226 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
227 Otherwise, it is the VALUE_LEN. */
233 name
= XNEWVEC (char, name_len
+ 1);
234 strncpy (name
, name_start
, name_len
);
235 name
[name_len
] = '\0';
237 /* Check if the named plugin has already been specified earlier in the
239 if (plugin_name_args_tab
240 && ((slot
= htab_find_slot (plugin_name_args_tab
, name
, NO_INSERT
))
243 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
245 key
= XNEWVEC (char, key_len
+ 1);
246 strncpy (key
, key_start
, key_len
);
250 value
= XNEWVEC (char, value_len
+ 1);
251 strncpy (value
, value_start
, value_len
);
252 value
[value_len
] = '\0';
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)
264 struct plugin_argument
*args
= XNEWVEC (struct plugin_argument
,
266 memcpy (args
, plugin
->argv
,
267 sizeof (struct plugin_argument
) * plugin
->argc
);
268 XDELETEVEC (plugin
->argv
);
274 gcc_assert (plugin
->argv
== NULL
);
275 plugin
->argv
= XNEWVEC (struct plugin_argument
, 1);
279 plugin
->argv
[plugin
->argc
- 1].key
= key
;
280 plugin
->argv
[plugin
->argc
- 1].value
= value
;
283 error ("Plugin %s should be specified before -fplugin-arg-%s "
284 "in the command line", name
, arg
);
286 /* We don't need the plugin's name anymore. Just release it. */
291 /* Insert the plugin pass at the proper position. Return true if the pass
292 is successfully added.
294 PLUGIN_PASS_INFO - new pass to be inserted
295 PASS_LIST - root of the pass list to insert the new pass to */
298 position_pass (struct plugin_pass
*plugin_pass_info
,
299 struct opt_pass
**pass_list
)
301 struct opt_pass
*pass
= *pass_list
, *prev_pass
= NULL
;
302 bool success
= false;
304 for ( ; pass
; prev_pass
= pass
, pass
= pass
->next
)
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
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
)))
317 struct opt_pass
*new_pass
= plugin_pass_info
->pass
;
318 struct pass_list_node
*new_pass_node
;
320 /* The following code (if-statement) is adopted from next_pass_1. */
321 if (new_pass
->static_pass_number
)
323 new_pass
= XNEW (struct opt_pass
);
324 memcpy (new_pass
, plugin_pass_info
->pass
, sizeof (*new_pass
));
325 new_pass
->next
= NULL
;
327 new_pass
->todo_flags_start
&= ~TODO_mark_first_instance
;
329 plugin_pass_info
->pass
->static_pass_number
-= 1;
330 new_pass
->static_pass_number
=
331 -plugin_pass_info
->pass
->static_pass_number
;
335 new_pass
->todo_flags_start
|= TODO_mark_first_instance
;
336 new_pass
->static_pass_number
= -1;
339 /* Insert the new pass instance based on the positioning op. */
340 switch (plugin_pass_info
->pos_op
)
342 case PASS_POS_INSERT_AFTER
:
343 new_pass
->next
= pass
->next
;
344 pass
->next
= new_pass
;
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. */
351 case PASS_POS_INSERT_BEFORE
:
352 new_pass
->next
= pass
;
354 prev_pass
->next
= new_pass
;
356 *pass_list
= new_pass
;
358 case PASS_POS_REPLACE
:
359 new_pass
->next
= pass
->next
;
361 prev_pass
->next
= new_pass
;
363 *pass_list
= new_pass
;
364 new_pass
->sub
= pass
->sub
;
365 new_pass
->tv_id
= pass
->tv_id
;
369 error ("Invalid pass positioning operation");
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
;
383 prev_added_pass_node
->next
= new_pass_node
;
384 prev_added_pass_node
= new_pass_node
;
389 if (pass
->sub
&& position_pass (plugin_pass_info
, &pass
->sub
))
397 /* Hook into the pass lists (trees) a new pass registered by a plugin.
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
405 register_pass (const char *plugin_name
, struct plugin_pass
*pass_info
)
407 if (!pass_info
->pass
)
409 error ("No pass specified when registering a new pass in plugin %s",
414 if (!pass_info
->reference_pass_name
)
416 error ("No reference pass specified for positioning the pass "
417 " from plugin %s", plugin_name
);
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
);
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
)
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
)
448 else if (added_pass_nodes
->pass
->type
== GIMPLE_PASS
)
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
;
463 /* Register additional plugin information. NAME is the name passed to
464 plugin_init. INFO is the information that should be registered. */
467 register_plugin_info (const char* name
, struct plugin_info
*info
)
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
;
475 /* Called from the plugin's initialization code. Register a single callback.
476 This function can be called multiple times.
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 */
484 register_callback (const char *plugin_name
,
485 enum plugin_event event
,
486 plugin_callback_func callback
,
491 case PLUGIN_PASS_MANAGER_SETUP
:
492 gcc_assert (!callback
);
493 register_pass (plugin_name
, (struct plugin_pass
*) user_data
);
496 gcc_assert (!callback
);
497 register_plugin_info (plugin_name
, (struct plugin_info
*) user_data
);
499 case PLUGIN_REGISTER_GGC_ROOTS
:
500 gcc_assert (!callback
);
501 ggc_register_root_tab ((const struct ggc_root_tab
*) user_data
);
503 case PLUGIN_REGISTER_GGC_CACHES
:
504 gcc_assert (!callback
);
505 ggc_register_cache_tab ((const struct ggc_cache_tab
*) user_data
);
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
:
514 case PLUGIN_ATTRIBUTES
:
517 struct callback_info
*new_callback
;
520 error ("Plugin %s registered a null callback function "
521 "for event %s", plugin_name
, plugin_event_name
[event
]);
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
;
532 case PLUGIN_EVENT_LAST
:
534 error ("Unkown callback event registered by plugin %s",
540 /* Called from inside GCC. Invoke all plug-in callbacks registered with
543 EVENT - the event identifier
544 GCC_DATA - event-specific data provided by the compiler */
547 invoke_plugin_callbacks (enum plugin_event event
, void *gcc_data
)
549 timevar_push (TV_PLUGIN_RUN
);
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
:
559 case PLUGIN_GGC_START
:
560 case PLUGIN_GGC_MARKING
:
563 /* Iterate over every callback registered with this event and
565 struct callback_info
*callback
= plugin_callbacks
[event
];
566 for ( ; callback
; callback
= callback
->next
)
567 (*callback
->func
) (gcc_data
, callback
->user_data
);
571 case PLUGIN_PASS_MANAGER_SETUP
:
572 case PLUGIN_EVENT_LAST
:
573 case PLUGIN_REGISTER_GGC_ROOTS
:
574 case PLUGIN_REGISTER_GGC_CACHES
:
579 timevar_pop (TV_PLUGIN_RUN
);
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
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)
591 /* Try to initialize PLUGIN. Return true if successful. */
594 try_init_one_plugin (struct plugin_name_args
*plugin
)
597 plugin_init_func plugin_init
;
599 PTR_UNION_TYPE (plugin_init_func
) plugin_init_union
;
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
605 dl_handle
= dlopen (plugin
->full_name
, RTLD_NOW
| RTLD_GLOBAL
);
608 error ("Cannot load plugin %s\n%s", plugin
->full_name
, dlerror ());
612 /* Clear any existing error. */
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 ());
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
);
624 if ((err
= dlerror ()) != NULL
)
626 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name
,
627 plugin
->full_name
, err
);
631 /* Call the plugin-provided initialization routine with the arguments. */
632 if ((*plugin_init
) (plugin
, &gcc_version
))
634 error ("Fail to initialize plugin %s", plugin
->full_name
);
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.
646 SLOT - slot of the hash table element
647 INFO - auxiliary pointer handed to hash table traverse routine
648 (unused in this function) */
651 init_one_plugin (void **slot
, void * ARG_UNUSED (info
))
653 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
654 bool ok
= try_init_one_plugin (plugin
);
657 htab_remove_elt (plugin_name_args_tab
, plugin
->base_name
);
663 #endif /* ENABLE_PLUGIN */
665 /* Main plugin initialization function. Called from compile_file() in
669 initialize_plugins (void)
671 /* If no plugin was specified in the command-line, simply return. */
672 if (!plugin_name_args_tab
)
675 timevar_push (TV_PLUGIN_INIT
);
678 /* Traverse and initialize each plugin specified in the command-line. */
679 htab_traverse_noresize (plugin_name_args_tab
, init_one_plugin
, NULL
);
682 timevar_pop (TV_PLUGIN_INIT
);
685 /* Release memory used by one plugin. */
688 finalize_one_plugin (void **slot
, void * ARG_UNUSED (info
))
690 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
695 /* Free memory allocated by the plugin system. */
698 finalize_plugins (void)
700 if (!plugin_name_args_tab
)
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
708 htab_traverse_noresize (plugin_name_args_tab
, finalize_one_plugin
, NULL
);
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
;
715 /* Used to pass options to htab_traverse callbacks. */
723 /* Print the version of one plugin. */
726 print_version_one_plugin (void **slot
, void *data
)
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.";
732 fprintf (opt
->file
, " %s%s: %s\n", opt
->indent
, plugin
->base_name
, version
);
736 /* Print the version of each plugin. */
739 print_plugins_versions (FILE *file
, const char *indent
)
741 struct print_options opt
;
744 if (!plugin_name_args_tab
|| htab_elements (plugin_name_args_tab
) == 0)
747 fprintf (file
, "%sVersions of loaded plugins:\n", indent
);
748 htab_traverse_noresize (plugin_name_args_tab
, print_version_one_plugin
, &opt
);
751 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
752 argument to htab_traverse_noresize. */
755 print_help_one_plugin (void **slot
, void *data
)
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 .";
761 char *dup
= xstrdup (help
);
763 fprintf (opt
->file
, " %s%s:\n", opt
->indent
, plugin
->base_name
);
765 for (p
= nl
= dup
; nl
; p
= nl
)
767 nl
= strchr (nl
, '\n');
773 fprintf (opt
->file
, " %s %s\n", opt
->indent
, p
);
780 /* Print help for each plugin. The output goes to FILE and every line starts
784 print_plugins_help (FILE *file
, const char *indent
)
786 struct print_options opt
;
789 if (!plugin_name_args_tab
|| htab_elements (plugin_name_args_tab
) == 0)
792 fprintf (file
, "%sHelp for the loaded plugins:\n", indent
);
793 htab_traverse_noresize (plugin_name_args_tab
, print_help_one_plugin
, &opt
);
797 /* Return true if plugins have been loaded. */
800 plugins_active_p (void)
804 for (event
= PLUGIN_PASS_MANAGER_SETUP
; event
< PLUGIN_EVENT_LAST
; event
++)
805 if (plugin_callbacks
[event
])
812 /* Dump to FILE the names and associated events for all the active
816 dump_active_plugins (FILE *file
)
820 if (!plugins_active_p ())
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
])
827 struct callback_info
*ci
;
829 fprintf (file
, "%s\t", plugin_event_name
[event
]);
831 for (ci
= plugin_callbacks
[event
]; ci
; ci
= ci
->next
)
832 fprintf (file
, "%s ", ci
->plugin_name
);
834 fprintf (file
, "\n");
839 /* Dump active plugins to stderr. */
842 debug_active_plugins (void)
844 dump_active_plugins (stderr
);
847 /* The default version check. Compares every field in VERSION. */
850 plugin_default_version_check (struct plugin_gcc_version
*gcc_version
,
851 struct plugin_gcc_version
*plugin_version
)
853 if (!gcc_version
|| !plugin_version
)
856 if (strcmp (gcc_version
->basever
, plugin_version
->basever
))
858 if (strcmp (gcc_version
->datestamp
, plugin_version
->datestamp
))
860 if (strcmp (gcc_version
->devphase
, plugin_version
->devphase
))
862 if (strcmp (gcc_version
->revision
, plugin_version
->revision
))
864 if (strcmp (gcc_version
->configuration_arguments
,
865 plugin_version
->configuration_arguments
))