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",
67 /* A printf format large enough for the largest event above. */
68 #define FMT_FOR_PLUGIN_EVENT "%-26s"
70 /* Hash table for the plugin_name_args objects created during command-line
72 static htab_t plugin_name_args_tab
= NULL
;
74 /* List node for keeping track of plugin-registered callback. */
77 const char *plugin_name
; /* Name of plugin that registers the callback. */
78 plugin_callback_func func
; /* Callback to be called. */
79 void *user_data
; /* plugin-specified data. */
80 struct callback_info
*next
;
83 /* An array of lists of 'callback_info' objects indexed by the event id. */
84 static struct callback_info
*plugin_callbacks
[PLUGIN_EVENT_LAST
] = { NULL
};
88 /* Each plugin should define an initialization function with exactly
90 static const char *str_plugin_init_func_name
= "plugin_init";
92 /* Each plugin should define this symbol to assert that it is
93 distributed under a GPL-compatible license. */
94 static const char *str_license
= "plugin_is_GPL_compatible";
97 /* Helper function for the hash table that compares the base_name of the
98 existing entry (S1) with the given string (S2). */
101 htab_str_eq (const void *s1
, const void *s2
)
103 const struct plugin_name_args
*plugin
= (const struct plugin_name_args
*) s1
;
104 return !strcmp (plugin
->base_name
, (const char *) s2
);
108 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
112 get_plugin_base_name (const char *full_name
)
114 /* First get the base name part of the full-path name, i.e. NAME.so. */
115 char *base_name
= xstrdup (lbasename (full_name
));
117 /* Then get rid of '.so' part of the name. */
118 strip_off_ending (base_name
, strlen (base_name
));
124 /* Create a plugin_name_args object for the give plugin and insert it to
125 the hash table. This function is called when -fplugin=/path/to/NAME.so
126 option is processed. */
129 add_new_plugin (const char* plugin_name
)
131 struct plugin_name_args
*plugin
;
133 char *base_name
= get_plugin_base_name (plugin_name
);
135 /* If this is the first -fplugin= option we encounter, create
136 'plugin_name_args_tab' hash table. */
137 if (!plugin_name_args_tab
)
138 plugin_name_args_tab
= htab_create (10, htab_hash_string
, htab_str_eq
,
141 slot
= htab_find_slot (plugin_name_args_tab
, base_name
, INSERT
);
143 /* If the same plugin (name) has been specified earlier, either emit an
144 error or a warning message depending on if they have identical full
148 plugin
= (struct plugin_name_args
*) *slot
;
149 if (strcmp (plugin
->full_name
, plugin_name
))
150 error ("Plugin %s was specified with different paths:\n%s\n%s",
151 plugin
->base_name
, plugin
->full_name
, plugin_name
);
155 plugin
= XCNEW (struct plugin_name_args
);
156 plugin
->base_name
= base_name
;
157 plugin
->full_name
= plugin_name
;
163 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
164 'plugin_argument' object for the parsed key-value pair. ARG is
165 the <name>-<key>[=<value>] part of the option. */
168 parse_plugin_arg_opt (const char *arg
)
170 size_t len
= 0, name_len
= 0, key_len
= 0, value_len
= 0;
171 const char *ptr
, *name_start
= arg
, *key_start
= NULL
, *value_start
= NULL
;
172 char *name
, *key
, *value
;
174 bool name_parsed
= false, key_parsed
= false;
176 /* Iterate over the ARG string and identify the starting character position
177 of 'name', 'key', and 'value' and their lengths. */
178 for (ptr
= arg
; *ptr
; ++ptr
)
180 /* Only the first '-' encountered is considered a separator between
181 'name' and 'key'. All the subsequent '-'s are considered part of
182 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
183 the plugin name is 'foo' and the key is 'bar-primary-key'. */
184 if (*ptr
== '-' && !name_parsed
)
192 else if (*ptr
== '=')
196 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
202 value_start
= ptr
+ 1;
212 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
217 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
218 Otherwise, it is the VALUE_LEN. */
224 name
= XNEWVEC (char, name_len
+ 1);
225 strncpy (name
, name_start
, name_len
);
226 name
[name_len
] = '\0';
228 /* Check if the named plugin has already been specified earlier in the
230 if (plugin_name_args_tab
231 && ((slot
= htab_find_slot (plugin_name_args_tab
, name
, NO_INSERT
))
234 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
236 key
= XNEWVEC (char, key_len
+ 1);
237 strncpy (key
, key_start
, key_len
);
241 value
= XNEWVEC (char, value_len
+ 1);
242 strncpy (value
, value_start
, value_len
);
243 value
[value_len
] = '\0';
248 /* Create a plugin_argument object for the parsed key-value pair.
249 If there are already arguments for this plugin, we will need to
250 adjust the argument array size by creating a new array and deleting
251 the old one. If the performance ever becomes an issue, we can
252 change the code by pre-allocating a larger array first. */
253 if (plugin
->argc
> 0)
255 struct plugin_argument
*args
= XNEWVEC (struct plugin_argument
,
257 memcpy (args
, plugin
->argv
,
258 sizeof (struct plugin_argument
) * plugin
->argc
);
259 XDELETEVEC (plugin
->argv
);
265 gcc_assert (plugin
->argv
== NULL
);
266 plugin
->argv
= XNEWVEC (struct plugin_argument
, 1);
270 plugin
->argv
[plugin
->argc
- 1].key
= key
;
271 plugin
->argv
[plugin
->argc
- 1].value
= value
;
274 error ("Plugin %s should be specified before -fplugin-arg-%s "
275 "in the command line", name
, arg
);
277 /* We don't need the plugin's name anymore. Just release it. */
281 /* Register additional plugin information. NAME is the name passed to
282 plugin_init. INFO is the information that should be registered. */
285 register_plugin_info (const char* name
, struct plugin_info
*info
)
287 void **slot
= htab_find_slot (plugin_name_args_tab
, name
, NO_INSERT
);
288 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
289 plugin
->version
= info
->version
;
290 plugin
->help
= info
->help
;
293 /* Called from the plugin's initialization code. Register a single callback.
294 This function can be called multiple times.
296 PLUGIN_NAME - display name for this plugin
297 EVENT - which event the callback is for
298 CALLBACK - the callback to be called at the event
299 USER_DATA - plugin-provided data */
302 register_callback (const char *plugin_name
,
303 enum plugin_event event
,
304 plugin_callback_func callback
,
309 case PLUGIN_PASS_MANAGER_SETUP
:
310 gcc_assert (!callback
);
311 register_pass ((struct register_pass_info
*) user_data
);
314 gcc_assert (!callback
);
315 register_plugin_info (plugin_name
, (struct plugin_info
*) user_data
);
317 case PLUGIN_REGISTER_GGC_ROOTS
:
318 gcc_assert (!callback
);
319 ggc_register_root_tab ((const struct ggc_root_tab
*) user_data
);
321 case PLUGIN_REGISTER_GGC_CACHES
:
322 gcc_assert (!callback
);
323 ggc_register_cache_tab ((const struct ggc_cache_tab
*) user_data
);
325 case PLUGIN_FINISH_TYPE
:
326 case PLUGIN_START_UNIT
:
327 case PLUGIN_FINISH_UNIT
:
328 case PLUGIN_CXX_CP_PRE_GENERICIZE
:
329 case PLUGIN_GGC_START
:
330 case PLUGIN_GGC_MARKING
:
332 case PLUGIN_ATTRIBUTES
:
336 struct callback_info
*new_callback
;
339 error ("Plugin %s registered a null callback function "
340 "for event %s", plugin_name
, plugin_event_name
[event
]);
343 new_callback
= XNEW (struct callback_info
);
344 new_callback
->plugin_name
= plugin_name
;
345 new_callback
->func
= callback
;
346 new_callback
->user_data
= user_data
;
347 new_callback
->next
= plugin_callbacks
[event
];
348 plugin_callbacks
[event
] = new_callback
;
351 case PLUGIN_EVENT_LAST
:
353 error ("Unknown callback event registered by plugin %s",
359 /* Called from inside GCC. Invoke all plug-in callbacks registered with
362 EVENT - the event identifier
363 GCC_DATA - event-specific data provided by the compiler */
366 invoke_plugin_callbacks (enum plugin_event event
, void *gcc_data
)
368 timevar_push (TV_PLUGIN_RUN
);
372 case PLUGIN_FINISH_TYPE
:
373 case PLUGIN_START_UNIT
:
374 case PLUGIN_FINISH_UNIT
:
375 case PLUGIN_CXX_CP_PRE_GENERICIZE
:
376 case PLUGIN_ATTRIBUTES
:
379 case PLUGIN_GGC_START
:
380 case PLUGIN_GGC_MARKING
:
383 /* Iterate over every callback registered with this event and
385 struct callback_info
*callback
= plugin_callbacks
[event
];
386 for ( ; callback
; callback
= callback
->next
)
387 (*callback
->func
) (gcc_data
, callback
->user_data
);
391 case PLUGIN_PASS_MANAGER_SETUP
:
392 case PLUGIN_EVENT_LAST
:
393 case PLUGIN_REGISTER_GGC_ROOTS
:
394 case PLUGIN_REGISTER_GGC_CACHES
:
399 timevar_pop (TV_PLUGIN_RUN
);
403 /* We need a union to cast dlsym return value to a function pointer
404 as ISO C forbids assignment between function pointer and 'void *'.
405 Use explicit union instead of __extension__(<union_cast>) for
407 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
408 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
409 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
411 /* Try to initialize PLUGIN. Return true if successful. */
414 try_init_one_plugin (struct plugin_name_args
*plugin
)
417 plugin_init_func plugin_init
;
419 PTR_UNION_TYPE (plugin_init_func
) plugin_init_union
;
421 /* We use RTLD_NOW to accelerate binding and detect any mismatch
422 between the API expected by the plugin and the GCC API; we use
423 RTLD_GLOBAL which is useful to plugins which themselves call
425 dl_handle
= dlopen (plugin
->full_name
, RTLD_NOW
| RTLD_GLOBAL
);
428 error ("Cannot load plugin %s\n%s", plugin
->full_name
, dlerror ());
432 /* Clear any existing error. */
435 /* Check the plugin license. */
436 if (dlsym (dl_handle
, str_license
) == NULL
)
437 fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
438 "%s", plugin
->full_name
, dlerror ());
440 PTR_UNION_AS_VOID_PTR (plugin_init_union
) =
441 dlsym (dl_handle
, str_plugin_init_func_name
);
442 plugin_init
= PTR_UNION_AS_CAST_PTR (plugin_init_union
);
444 if ((err
= dlerror ()) != NULL
)
446 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name
,
447 plugin
->full_name
, err
);
451 /* Call the plugin-provided initialization routine with the arguments. */
452 if ((*plugin_init
) (plugin
, &gcc_version
))
454 error ("Fail to initialize plugin %s", plugin
->full_name
);
462 /* Routine to dlopen and initialize one plugin. This function is passed to
463 (and called by) the hash table traverse routine. Return 1 for the
464 htab_traverse to continue scan, 0 to stop.
466 SLOT - slot of the hash table element
467 INFO - auxiliary pointer handed to hash table traverse routine
468 (unused in this function) */
471 init_one_plugin (void **slot
, void * ARG_UNUSED (info
))
473 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
474 bool ok
= try_init_one_plugin (plugin
);
477 htab_remove_elt (plugin_name_args_tab
, plugin
->base_name
);
483 #endif /* ENABLE_PLUGIN */
485 /* Main plugin initialization function. Called from compile_file() in
489 initialize_plugins (void)
491 /* If no plugin was specified in the command-line, simply return. */
492 if (!plugin_name_args_tab
)
495 timevar_push (TV_PLUGIN_INIT
);
498 /* Traverse and initialize each plugin specified in the command-line. */
499 htab_traverse_noresize (plugin_name_args_tab
, init_one_plugin
, NULL
);
502 timevar_pop (TV_PLUGIN_INIT
);
505 /* Release memory used by one plugin. */
508 finalize_one_plugin (void **slot
, void * ARG_UNUSED (info
))
510 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
515 /* Free memory allocated by the plugin system. */
518 finalize_plugins (void)
520 if (!plugin_name_args_tab
)
523 /* We can now delete the plugin_name_args object as it will no longer
524 be used. Note that base_name and argv fields (both of which were also
525 dynamically allocated) are not freed as they could still be used by
528 htab_traverse_noresize (plugin_name_args_tab
, finalize_one_plugin
, NULL
);
530 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
531 htab_delete (plugin_name_args_tab
);
532 plugin_name_args_tab
= NULL
;
535 /* Used to pass options to htab_traverse callbacks. */
543 /* Print the version of one plugin. */
546 print_version_one_plugin (void **slot
, void *data
)
548 struct print_options
*opt
= (struct print_options
*) data
;
549 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
550 const char *version
= plugin
->version
? plugin
->version
: "Unknown version.";
552 fprintf (opt
->file
, " %s%s: %s\n", opt
->indent
, plugin
->base_name
, version
);
556 /* Print the version of each plugin. */
559 print_plugins_versions (FILE *file
, const char *indent
)
561 struct print_options opt
;
564 if (!plugin_name_args_tab
|| htab_elements (plugin_name_args_tab
) == 0)
567 fprintf (file
, "%sVersions of loaded plugins:\n", indent
);
568 htab_traverse_noresize (plugin_name_args_tab
, print_version_one_plugin
, &opt
);
571 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
572 argument to htab_traverse_noresize. */
575 print_help_one_plugin (void **slot
, void *data
)
577 struct print_options
*opt
= (struct print_options
*) data
;
578 struct plugin_name_args
*plugin
= (struct plugin_name_args
*) *slot
;
579 const char *help
= plugin
->help
? plugin
->help
: "No help available .";
581 char *dup
= xstrdup (help
);
583 fprintf (opt
->file
, " %s%s:\n", opt
->indent
, plugin
->base_name
);
585 for (p
= nl
= dup
; nl
; p
= nl
)
587 nl
= strchr (nl
, '\n');
593 fprintf (opt
->file
, " %s %s\n", opt
->indent
, p
);
600 /* Print help for each plugin. The output goes to FILE and every line starts
604 print_plugins_help (FILE *file
, const char *indent
)
606 struct print_options opt
;
609 if (!plugin_name_args_tab
|| htab_elements (plugin_name_args_tab
) == 0)
612 fprintf (file
, "%sHelp for the loaded plugins:\n", indent
);
613 htab_traverse_noresize (plugin_name_args_tab
, print_help_one_plugin
, &opt
);
617 /* Return true if plugins have been loaded. */
620 plugins_active_p (void)
624 for (event
= PLUGIN_PASS_MANAGER_SETUP
; event
< PLUGIN_EVENT_LAST
; event
++)
625 if (plugin_callbacks
[event
])
632 /* Dump to FILE the names and associated events for all the active
636 dump_active_plugins (FILE *file
)
640 if (!plugins_active_p ())
643 fprintf (file
, FMT_FOR_PLUGIN_EVENT
" | %s\n", _("Event"), _("Plugins"));
644 for (event
= PLUGIN_PASS_MANAGER_SETUP
; event
< PLUGIN_EVENT_LAST
; event
++)
645 if (plugin_callbacks
[event
])
647 struct callback_info
*ci
;
649 fprintf (file
, FMT_FOR_PLUGIN_EVENT
" |", plugin_event_name
[event
]);
651 for (ci
= plugin_callbacks
[event
]; ci
; ci
= ci
->next
)
652 fprintf (file
, " %s", ci
->plugin_name
);
659 /* Dump active plugins to stderr. */
662 debug_active_plugins (void)
664 dump_active_plugins (stderr
);
667 /* The default version check. Compares every field in VERSION. */
670 plugin_default_version_check (struct plugin_gcc_version
*gcc_version
,
671 struct plugin_gcc_version
*plugin_version
)
673 if (!gcc_version
|| !plugin_version
)
676 if (strcmp (gcc_version
->basever
, plugin_version
->basever
))
678 if (strcmp (gcc_version
->datestamp
, plugin_version
->datestamp
))
680 if (strcmp (gcc_version
->devphase
, plugin_version
->devphase
))
682 if (strcmp (gcc_version
->revision
, plugin_version
->revision
))
684 if (strcmp (gcc_version
->configuration_arguments
,
685 plugin_version
->configuration_arguments
))