Line data Source code
1 : /* Support for GCC plugin mechanism.
2 : Copyright (C) 2009-2026 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 : #define INCLUDE_DLFCN_H
25 : #include "system.h"
26 : #include "coretypes.h"
27 : #include "options.h"
28 : #include "tree-pass.h"
29 : #include "diagnostic-core.h"
30 : #include "flags.h"
31 : #include "intl.h"
32 : #include "plugin.h"
33 :
34 : #ifdef ENABLE_PLUGIN
35 : #include "plugin-version.h"
36 : #endif
37 :
38 : #ifdef __MINGW32__
39 : #ifndef WIN32_LEAN_AND_MEAN
40 : #define WIN32_LEAN_AND_MEAN
41 : #endif
42 : #ifndef NOMINMAX
43 : #define NOMINMAX
44 : #endif
45 : #define WIN32_LEAN_AND_MEAN
46 : #include <windows.h>
47 : #endif
48 :
49 : #define GCC_PLUGIN_STRINGIFY0(X) #X
50 : #define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
51 :
52 : /* Event names as strings. Keep in sync with enum plugin_event. */
53 : static const char *plugin_event_name_init[] =
54 : {
55 : # define DEFEVENT(NAME) GCC_PLUGIN_STRINGIFY1 (NAME),
56 : # include "plugin.def"
57 : # undef DEFEVENT
58 : };
59 :
60 : /* A printf format large enough for the largest event above. */
61 : #define FMT_FOR_PLUGIN_EVENT "%-32s"
62 :
63 : const char **plugin_event_name = plugin_event_name_init;
64 :
65 : /* Event hashtable helpers. */
66 :
67 : struct event_hasher : nofree_ptr_hash <const char *>
68 : {
69 : static inline hashval_t hash (const char **);
70 : static inline bool equal (const char **, const char **);
71 : };
72 :
73 : /* Helper function for the event hash table that hashes the entry V. */
74 :
75 : inline hashval_t
76 0 : event_hasher::hash (const char **v)
77 : {
78 0 : return htab_hash_string (*v);
79 : }
80 :
81 : /* Helper function for the event hash table that compares the name of an
82 : existing entry (S1) with the given string (S2). */
83 :
84 : inline bool
85 0 : event_hasher::equal (const char **s1, const char **s2)
86 : {
87 0 : return !strcmp (*s1, *s2);
88 : }
89 :
90 : /* A hash table to map event names to the position of the names in the
91 : plugin_event_name table. */
92 : static hash_table<event_hasher> *event_tab;
93 :
94 : /* Keep track of the limit of allocated events and space ready for
95 : allocating events. */
96 : static int event_last = PLUGIN_EVENT_FIRST_DYNAMIC;
97 : static int event_horizon = PLUGIN_EVENT_FIRST_DYNAMIC;
98 :
99 : /* Hash table for the plugin_name_args objects created during command-line
100 : parsing. */
101 : static htab_t plugin_name_args_tab = NULL;
102 :
103 : /* List node for keeping track of plugin-registered callback. */
104 : struct callback_info
105 : {
106 : const char *plugin_name; /* Name of plugin that registers the callback. */
107 : plugin_callback_func func; /* Callback to be called. */
108 : void *user_data; /* plugin-specified data. */
109 : struct callback_info *next;
110 : };
111 :
112 : /* An array of lists of 'callback_info' objects indexed by the event id. */
113 : static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_FIRST_DYNAMIC];
114 : static struct callback_info **plugin_callbacks = plugin_callbacks_init;
115 :
116 : /* For invoke_plugin_callbacks(), see plugin.h. */
117 : bool flag_plugin_added = false;
118 :
119 : #ifdef ENABLE_PLUGIN
120 : /* Each plugin should define an initialization function with exactly
121 : this name. */
122 : static const char *str_plugin_init_func_name = "plugin_init";
123 :
124 : /* Each plugin should define this symbol to assert that it is
125 : distributed under a GPL-compatible license. */
126 : static const char *str_license = "plugin_is_GPL_compatible";
127 : #endif
128 :
129 : /* Helper function for hashing the base_name of the plugin_name_args
130 : structure to be inserted into the hash table. */
131 :
132 : static hashval_t
133 0 : htab_hash_plugin (const void *p)
134 : {
135 0 : const struct plugin_name_args *plugin = (const struct plugin_name_args *) p;
136 0 : return htab_hash_string (plugin->base_name);
137 : }
138 :
139 : /* Helper function for the hash table that compares the base_name of the
140 : existing entry (S1) with the given string (S2). */
141 :
142 : static int
143 17 : htab_str_eq (const void *s1, const void *s2)
144 : {
145 17 : const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
146 17 : return !strcmp (plugin->base_name, (const char *) s2);
147 : }
148 :
149 :
150 : /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
151 : return NAME. */
152 :
153 : static char *
154 146 : get_plugin_base_name (const char *full_name)
155 : {
156 : /* First get the base name part of the full-path name, i.e. NAME.so. */
157 146 : char *base_name = xstrdup (lbasename (full_name));
158 :
159 : /* Then get rid of the extension in the name, e.g., .so. */
160 146 : strip_off_ending (base_name, strlen (base_name));
161 :
162 146 : return base_name;
163 : }
164 :
165 :
166 : /* Create a plugin_name_args object for the given plugin and insert it
167 : to the hash table. This function is called when
168 : -fplugin=/path/to/NAME.so or -fplugin=NAME option is processed. */
169 :
170 : void
171 257 : add_new_plugin (const char* plugin_name)
172 : {
173 257 : struct plugin_name_args *plugin;
174 257 : void **slot;
175 257 : char *base_name;
176 257 : bool name_is_short;
177 257 : const char *pc;
178 :
179 257 : flag_plugin_added = true;
180 :
181 : /* Replace short names by their full path when relevant. */
182 257 : name_is_short = !IS_ABSOLUTE_PATH (plugin_name);
183 950 : for (pc = plugin_name; name_is_short && *pc; pc++)
184 693 : if (*pc == '.' || IS_DIR_SEPARATOR (*pc))
185 146 : name_is_short = false;
186 :
187 257 : if (name_is_short)
188 : {
189 111 : base_name = const_cast<char*> (plugin_name);
190 :
191 : #if defined(__MINGW32__)
192 : static const char plugin_ext[] = ".dll";
193 : #elif defined(__APPLE__)
194 : /* macOS has two types of libraries: dynamic libraries (.dylib) and
195 : plugins (.bundle). Both can be used with dlopen()/dlsym() but the
196 : former cannot be linked at build time (i.e., with the -lfoo linker
197 : option). A GCC plugin is therefore probably a macOS plugin but their
198 : use seems to be quite rare and the .bundle extension is more of a
199 : recommendation rather than the rule. This raises the questions of how
200 : well they are supported by tools (e.g., libtool). So to avoid
201 : complications let's use the .dylib extension for now. In the future,
202 : if this proves to be an issue, we can always check for both
203 : extensions. */
204 : static const char plugin_ext[] = ".dylib";
205 : #else
206 111 : static const char plugin_ext[] = ".so";
207 : #endif
208 :
209 111 : plugin_name = concat (default_plugin_dir_name (), "/",
210 : plugin_name, plugin_ext, NULL);
211 111 : if (access (plugin_name, R_OK))
212 4 : fatal_error
213 4 : (input_location,
214 : "inaccessible plugin file %s expanded from short plugin name %s: %m",
215 : plugin_name, base_name);
216 : }
217 : else
218 146 : base_name = get_plugin_base_name (plugin_name);
219 :
220 : /* If this is the first -fplugin= option we encounter, create
221 : 'plugin_name_args_tab' hash table. */
222 253 : if (!plugin_name_args_tab)
223 253 : plugin_name_args_tab = htab_create (10, htab_hash_plugin, htab_str_eq,
224 : NULL);
225 :
226 253 : slot = htab_find_slot_with_hash (plugin_name_args_tab, base_name,
227 : htab_hash_string (base_name), INSERT);
228 :
229 : /* If the same plugin (name) has been specified earlier, either emit an
230 : error or a warning message depending on if they have identical full
231 : (path) names. */
232 253 : if (*slot)
233 : {
234 0 : plugin = (struct plugin_name_args *) *slot;
235 0 : if (strcmp (plugin->full_name, plugin_name))
236 0 : error ("plugin %qs was specified with different paths: %qs and %qs",
237 : plugin->base_name, plugin->full_name, plugin_name);
238 0 : return;
239 : }
240 :
241 253 : plugin = XCNEW (struct plugin_name_args);
242 253 : plugin->base_name = base_name;
243 253 : plugin->full_name = plugin_name;
244 :
245 253 : *slot = plugin;
246 : }
247 :
248 :
249 : /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
250 : 'plugin_argument' object for the parsed key-value pair. ARG is
251 : the <name>-<key>[=<value>] part of the option. */
252 :
253 : void
254 17 : parse_plugin_arg_opt (const char *arg)
255 : {
256 17 : size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
257 17 : const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
258 17 : char *name, *key, *value;
259 17 : void **slot;
260 17 : bool name_parsed = false, key_parsed = false;
261 :
262 : /* Iterate over the ARG string and identify the starting character position
263 : of 'name', 'key', and 'value' and their lengths. */
264 596 : for (ptr = arg; *ptr; ++ptr)
265 : {
266 : /* Only the first '-' encountered is considered a separator between
267 : 'name' and 'key'. All the subsequent '-'s are considered part of
268 : 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
269 : the plugin name is 'foo' and the key is 'bar-primary-key'. */
270 579 : if (*ptr == '-' && !name_parsed)
271 : {
272 17 : name_len = len;
273 17 : len = 0;
274 17 : key_start = ptr + 1;
275 17 : name_parsed = true;
276 17 : continue;
277 : }
278 562 : else if (*ptr == '=')
279 : {
280 10 : if (!key_parsed)
281 : {
282 10 : key_len = len;
283 10 : len = 0;
284 10 : value_start = ptr + 1;
285 10 : key_parsed = true;
286 : }
287 10 : continue;
288 : }
289 : else
290 552 : ++len;
291 : }
292 :
293 17 : if (!key_start)
294 : {
295 0 : error ("malformed option %<-fplugin-arg-%s%>: "
296 : "missing %<-<key>[=<value>]%>",
297 : arg);
298 0 : return;
299 : }
300 :
301 : /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
302 : Otherwise, it is the VALUE_LEN. */
303 17 : if (!value_start)
304 : key_len = len;
305 : else
306 10 : value_len = len;
307 :
308 17 : name = XNEWVEC (char, name_len + 1);
309 17 : strncpy (name, name_start, name_len);
310 17 : name[name_len] = '\0';
311 :
312 : /* Check if the named plugin has already been specified earlier in the
313 : command-line. */
314 17 : if (plugin_name_args_tab
315 17 : && ((slot = htab_find_slot_with_hash (plugin_name_args_tab, name,
316 : htab_hash_string (name), NO_INSERT))
317 : != NULL))
318 : {
319 17 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
320 :
321 17 : key = XNEWVEC (char, key_len + 1);
322 17 : strncpy (key, key_start, key_len);
323 17 : key[key_len] = '\0';
324 17 : if (value_start)
325 : {
326 10 : value = XNEWVEC (char, value_len + 1);
327 10 : strncpy (value, value_start, value_len);
328 10 : value[value_len] = '\0';
329 : }
330 : else
331 : value = NULL;
332 :
333 : /* Create a plugin_argument object for the parsed key-value pair.
334 : If there are already arguments for this plugin, we will need to
335 : adjust the argument array size by creating a new array and deleting
336 : the old one. If the performance ever becomes an issue, we can
337 : change the code by pre-allocating a larger array first. */
338 17 : if (plugin->argc > 0)
339 : {
340 1 : struct plugin_argument *args = XNEWVEC (struct plugin_argument,
341 : plugin->argc + 1);
342 1 : memcpy (args, plugin->argv,
343 1 : sizeof (struct plugin_argument) * plugin->argc);
344 1 : XDELETEVEC (plugin->argv);
345 1 : plugin->argv = args;
346 1 : ++plugin->argc;
347 : }
348 : else
349 : {
350 16 : gcc_assert (plugin->argv == NULL);
351 16 : plugin->argv = XNEWVEC (struct plugin_argument, 1);
352 16 : plugin->argc = 1;
353 : }
354 :
355 17 : plugin->argv[plugin->argc - 1].key = key;
356 17 : plugin->argv[plugin->argc - 1].value = value;
357 : }
358 : else
359 0 : error ("plugin %s should be specified before %<-fplugin-arg-%s%> "
360 : "in the command line", name, arg);
361 :
362 : /* We don't need the plugin's name anymore. Just release it. */
363 17 : XDELETEVEC (name);
364 : }
365 :
366 : /* Register additional plugin information. NAME is the name passed to
367 : plugin_init. INFO is the information that should be registered. */
368 :
369 : static void
370 0 : register_plugin_info (const char* name, struct plugin_info *info)
371 : {
372 0 : void **slot = htab_find_slot_with_hash (plugin_name_args_tab, name,
373 : htab_hash_string (name), NO_INSERT);
374 0 : struct plugin_name_args *plugin;
375 :
376 0 : if (slot == NULL)
377 : {
378 0 : error ("unable to register info for plugin %qs - plugin name not found",
379 : name);
380 0 : return;
381 : }
382 0 : plugin = (struct plugin_name_args *) *slot;
383 0 : plugin->version = info->version;
384 0 : plugin->help = info->help;
385 : }
386 :
387 : /* Look up the event id for NAME. If the name is not found, return -1
388 : if INSERT is NO_INSERT. */
389 :
390 : int
391 0 : get_named_event_id (const char *name, enum insert_option insert)
392 : {
393 0 : const char ***slot;
394 :
395 0 : if (!event_tab)
396 : {
397 0 : int i;
398 :
399 0 : event_tab = new hash_table<event_hasher> (150);
400 0 : for (i = 0; i < event_last; i++)
401 : {
402 0 : slot = event_tab->find_slot (&plugin_event_name[i], INSERT);
403 0 : gcc_assert (*slot == HTAB_EMPTY_ENTRY);
404 0 : *slot = &plugin_event_name[i];
405 : }
406 : }
407 0 : slot = event_tab->find_slot (&name, insert);
408 0 : if (slot == NULL)
409 : return -1;
410 0 : if (*slot != HTAB_EMPTY_ENTRY)
411 0 : return *slot - &plugin_event_name[0];
412 :
413 0 : if (event_last >= event_horizon)
414 : {
415 0 : event_horizon = event_last * 2;
416 0 : if (plugin_event_name == plugin_event_name_init)
417 : {
418 0 : plugin_event_name = XNEWVEC (const char *, event_horizon);
419 0 : memcpy (plugin_event_name, plugin_event_name_init,
420 : sizeof plugin_event_name_init);
421 0 : plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon);
422 0 : memcpy (plugin_callbacks, plugin_callbacks_init,
423 : sizeof plugin_callbacks_init);
424 : }
425 : else
426 : {
427 0 : plugin_event_name
428 0 : = XRESIZEVEC (const char *, plugin_event_name, event_horizon);
429 0 : plugin_callbacks = XRESIZEVEC (struct callback_info *,
430 : plugin_callbacks, event_horizon);
431 : }
432 : /* All the pointers in the hash table will need to be updated. */
433 0 : delete event_tab;
434 0 : event_tab = NULL;
435 : }
436 : else
437 0 : *slot = &plugin_event_name[event_last];
438 0 : plugin_event_name[event_last] = name;
439 0 : return event_last++;
440 : }
441 :
442 : /* Called from the plugin's initialization code. Register a single callback.
443 : This function can be called multiple times.
444 :
445 : PLUGIN_NAME - display name for this plugin
446 : EVENT - which event the callback is for
447 : CALLBACK - the callback to be called at the event
448 : USER_DATA - plugin-provided data */
449 :
450 : void
451 307 : register_callback (const char *plugin_name,
452 : int event,
453 : plugin_callback_func callback,
454 : void *user_data)
455 : {
456 307 : switch (event)
457 : {
458 173 : case PLUGIN_PASS_MANAGER_SETUP:
459 173 : gcc_assert (!callback);
460 173 : register_pass ((struct register_pass_info *) user_data);
461 173 : break;
462 0 : case PLUGIN_INFO:
463 0 : gcc_assert (!callback);
464 0 : register_plugin_info (plugin_name, (struct plugin_info *) user_data);
465 0 : break;
466 1 : case PLUGIN_REGISTER_GGC_ROOTS:
467 1 : gcc_assert (!callback);
468 1 : ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
469 1 : break;
470 0 : case PLUGIN_EVENT_FIRST_DYNAMIC:
471 0 : default:
472 0 : if (event < PLUGIN_EVENT_FIRST_DYNAMIC || event >= event_last)
473 : {
474 0 : error ("unknown callback event registered by plugin %s",
475 : plugin_name);
476 0 : return;
477 : }
478 : /* Fall through. */
479 133 : case PLUGIN_START_PARSE_FUNCTION:
480 133 : case PLUGIN_FINISH_PARSE_FUNCTION:
481 133 : case PLUGIN_FINISH_TYPE:
482 133 : case PLUGIN_FINISH_DECL:
483 133 : case PLUGIN_START_UNIT:
484 133 : case PLUGIN_FINISH_UNIT:
485 133 : case PLUGIN_PRE_GENERICIZE:
486 133 : case PLUGIN_GGC_START:
487 133 : case PLUGIN_GGC_MARKING:
488 133 : case PLUGIN_GGC_END:
489 133 : case PLUGIN_ATTRIBUTES:
490 133 : case PLUGIN_PRAGMAS:
491 133 : case PLUGIN_FINISH:
492 133 : case PLUGIN_ALL_PASSES_START:
493 133 : case PLUGIN_ALL_PASSES_END:
494 133 : case PLUGIN_ALL_IPA_PASSES_START:
495 133 : case PLUGIN_ALL_IPA_PASSES_END:
496 133 : case PLUGIN_OVERRIDE_GATE:
497 133 : case PLUGIN_PASS_EXECUTION:
498 133 : case PLUGIN_EARLY_GIMPLE_PASSES_START:
499 133 : case PLUGIN_EARLY_GIMPLE_PASSES_END:
500 133 : case PLUGIN_NEW_PASS:
501 133 : case PLUGIN_INCLUDE_FILE:
502 133 : {
503 133 : struct callback_info *new_callback;
504 133 : if (!callback)
505 : {
506 0 : error ("plugin %s registered a null callback function "
507 0 : "for event %s", plugin_name, plugin_event_name[event]);
508 0 : return;
509 : }
510 133 : new_callback = XNEW (struct callback_info);
511 133 : new_callback->plugin_name = plugin_name;
512 133 : new_callback->func = callback;
513 133 : new_callback->user_data = user_data;
514 133 : new_callback->next = plugin_callbacks[event];
515 133 : plugin_callbacks[event] = new_callback;
516 : }
517 133 : break;
518 : }
519 : }
520 :
521 : /* Remove a callback for EVENT which has been registered with for a plugin
522 : PLUGIN_NAME. Return PLUGEVT_SUCCESS if a matching callback was
523 : found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching
524 : callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid. */
525 : int
526 0 : unregister_callback (const char *plugin_name, int event)
527 : {
528 0 : struct callback_info *callback, **cbp;
529 :
530 0 : if (event >= event_last)
531 : return PLUGEVT_NO_SUCH_EVENT;
532 :
533 0 : for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next)
534 0 : if (strcmp (callback->plugin_name, plugin_name) == 0)
535 : {
536 0 : *cbp = callback->next;
537 0 : return PLUGEVT_SUCCESS;
538 : }
539 : return PLUGEVT_NO_CALLBACK;
540 : }
541 :
542 : /* Invoke all plugin callbacks registered with the specified event,
543 : called from invoke_plugin_callbacks(). */
544 :
545 : int
546 343937 : invoke_plugin_callbacks_full (int event, void *gcc_data)
547 : {
548 343937 : int retval = PLUGEVT_SUCCESS;
549 :
550 343937 : timevar_push (TV_PLUGIN_RUN);
551 :
552 343937 : switch (event)
553 : {
554 0 : case PLUGIN_EVENT_FIRST_DYNAMIC:
555 0 : default:
556 0 : gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC);
557 0 : gcc_assert (event < event_last);
558 : /* Fall through. */
559 343937 : case PLUGIN_START_PARSE_FUNCTION:
560 343937 : case PLUGIN_FINISH_PARSE_FUNCTION:
561 343937 : case PLUGIN_FINISH_TYPE:
562 343937 : case PLUGIN_FINISH_DECL:
563 343937 : case PLUGIN_START_UNIT:
564 343937 : case PLUGIN_FINISH_UNIT:
565 343937 : case PLUGIN_PRE_GENERICIZE:
566 343937 : case PLUGIN_ATTRIBUTES:
567 343937 : case PLUGIN_PRAGMAS:
568 343937 : case PLUGIN_FINISH:
569 343937 : case PLUGIN_GGC_START:
570 343937 : case PLUGIN_GGC_MARKING:
571 343937 : case PLUGIN_GGC_END:
572 343937 : case PLUGIN_ALL_PASSES_START:
573 343937 : case PLUGIN_ALL_PASSES_END:
574 343937 : case PLUGIN_ALL_IPA_PASSES_START:
575 343937 : case PLUGIN_ALL_IPA_PASSES_END:
576 343937 : case PLUGIN_OVERRIDE_GATE:
577 343937 : case PLUGIN_PASS_EXECUTION:
578 343937 : case PLUGIN_EARLY_GIMPLE_PASSES_START:
579 343937 : case PLUGIN_EARLY_GIMPLE_PASSES_END:
580 343937 : case PLUGIN_NEW_PASS:
581 343937 : case PLUGIN_INCLUDE_FILE:
582 343937 : {
583 : /* Iterate over every callback registered with this event and
584 : call it. */
585 343937 : struct callback_info *callback = plugin_callbacks[event];
586 :
587 343937 : if (!callback)
588 343684 : retval = PLUGEVT_NO_CALLBACK;
589 344190 : for ( ; callback; callback = callback->next)
590 253 : (*callback->func) (gcc_data, callback->user_data);
591 : }
592 343937 : break;
593 :
594 0 : case PLUGIN_PASS_MANAGER_SETUP:
595 0 : case PLUGIN_REGISTER_GGC_ROOTS:
596 0 : gcc_assert (false);
597 : }
598 :
599 343937 : timevar_pop (TV_PLUGIN_RUN);
600 343937 : return retval;
601 : }
602 :
603 : #ifdef ENABLE_PLUGIN
604 :
605 : /* Try to initialize PLUGIN. Return true if successful. */
606 :
607 : #ifdef __MINGW32__
608 :
609 : // Return a message string for last error or NULL if unknown. Must be freed
610 : // with LocalFree().
611 : static inline char *
612 : win32_error_msg ()
613 : {
614 : char *msg;
615 : return FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
616 : FORMAT_MESSAGE_FROM_SYSTEM |
617 : FORMAT_MESSAGE_IGNORE_INSERTS |
618 : FORMAT_MESSAGE_MAX_WIDTH_MASK,
619 : 0,
620 : GetLastError (),
621 : MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
622 : (char*)&msg,
623 : 0,
624 : 0)
625 : ? msg
626 : : NULL;
627 : }
628 :
629 : static bool
630 : try_init_one_plugin (struct plugin_name_args *plugin)
631 : {
632 : HMODULE dl_handle;
633 : plugin_init_func plugin_init;
634 :
635 : dl_handle = LoadLibrary (plugin->full_name);
636 : if (!dl_handle)
637 : {
638 : char *err = win32_error_msg ();
639 : error ("cannot load plugin %s\n%s", plugin->full_name, err);
640 : LocalFree (err);
641 : return false;
642 : }
643 :
644 : /* Check the plugin license. Unlike the name suggests, GetProcAddress()
645 : can be used for both functions and variables. */
646 : if (GetProcAddress (dl_handle, str_license) == NULL)
647 : {
648 : char *err = win32_error_msg ();
649 : fatal_error (input_location,
650 : "plugin %s is not licensed under a GPL-compatible license\n"
651 : "%s", plugin->full_name, err);
652 : }
653 :
654 : /* Unlike dlsym(), GetProcAddress() returns a pointer to a function so we
655 : can cast directly without union tricks. */
656 : plugin_init = (plugin_init_func)
657 : GetProcAddress (dl_handle, str_plugin_init_func_name);
658 :
659 : if (plugin_init == NULL)
660 : {
661 : char *err = win32_error_msg ();
662 : FreeLibrary (dl_handle);
663 : error ("cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
664 : plugin->full_name, err);
665 : LocalFree (err);
666 : return false;
667 : }
668 :
669 : /* Call the plugin-provided initialization routine with the arguments. */
670 : if ((*plugin_init) (plugin, &gcc_version))
671 : {
672 : FreeLibrary (dl_handle);
673 : error ("fail to initialize plugin %s", plugin->full_name);
674 : return false;
675 : }
676 : /* Leak dl_handle on purpose to ensure the plugin is loaded for the
677 : entire run of the compiler. */
678 : return true;
679 : }
680 :
681 : #else // POSIX-like with dlopen()/dlsym().
682 :
683 : /* We need a union to cast dlsym return value to a function pointer
684 : as ISO C forbids assignment between function pointer and 'void *'.
685 : Use explicit union instead of __extension__(<union_cast>) for
686 : portability. */
687 : #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
688 : #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
689 : #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
690 :
691 : static bool
692 253 : try_init_one_plugin (struct plugin_name_args *plugin)
693 : {
694 253 : void *dl_handle;
695 253 : plugin_init_func plugin_init;
696 253 : const char *err;
697 253 : PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
698 :
699 : /* We use RTLD_NOW to accelerate binding and detect any mismatch
700 : between the API expected by the plugin and the GCC API; we use
701 : RTLD_GLOBAL which is useful to plugins which themselves call
702 : dlopen. */
703 253 : dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
704 253 : if (!dl_handle)
705 : {
706 0 : error ("cannot load plugin %s: %s", plugin->full_name, dlerror ());
707 0 : return false;
708 : }
709 :
710 : /* Clear any existing error. */
711 253 : dlerror ();
712 :
713 : /* Check the plugin license. */
714 253 : if (dlsym (dl_handle, str_license) == NULL)
715 0 : fatal_error (input_location,
716 : "plugin %s is not licensed under a GPL-compatible license:"
717 : " %s", plugin->full_name, dlerror ());
718 :
719 253 : PTR_UNION_AS_VOID_PTR (plugin_init_union)
720 253 : = dlsym (dl_handle, str_plugin_init_func_name);
721 253 : plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
722 :
723 253 : if ((err = dlerror ()) != NULL)
724 : {
725 0 : dlclose(dl_handle);
726 0 : error ("cannot find %s in plugin %s: %s", str_plugin_init_func_name,
727 : plugin->full_name, err);
728 0 : return false;
729 : }
730 :
731 : /* Call the plugin-provided initialization routine with the arguments. */
732 253 : if ((*plugin_init) (plugin, &gcc_version))
733 : {
734 0 : dlclose(dl_handle);
735 0 : error ("failed to initialize plugin %s", plugin->full_name);
736 0 : return false;
737 : }
738 : /* leak dl_handle on purpose to ensure the plugin is loaded for the
739 : entire run of the compiler. */
740 : return true;
741 : }
742 : #endif
743 :
744 : /* Routine to dlopen and initialize one plugin. This function is passed to
745 : (and called by) the hash table traverse routine. Return 1 for the
746 : htab_traverse to continue scan, 0 to stop.
747 :
748 : SLOT - slot of the hash table element
749 : INFO - auxiliary pointer handed to hash table traverse routine
750 : (unused in this function) */
751 :
752 : static int
753 253 : init_one_plugin (void **slot, void * ARG_UNUSED (info))
754 : {
755 253 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
756 253 : bool ok = try_init_one_plugin (plugin);
757 253 : if (!ok)
758 : {
759 0 : htab_remove_elt_with_hash (plugin_name_args_tab, plugin->base_name,
760 0 : htab_hash_string (plugin->base_name));
761 0 : XDELETE (plugin);
762 : }
763 253 : return 1;
764 : }
765 :
766 : #endif /* ENABLE_PLUGIN */
767 :
768 : /* Main plugin initialization function. Called from compile_file() in
769 : toplev.cc. */
770 :
771 : void
772 285718 : initialize_plugins (void)
773 : {
774 : /* If no plugin was specified in the command-line, simply return. */
775 285718 : if (!plugin_name_args_tab)
776 : return;
777 :
778 253 : timevar_push (TV_PLUGIN_INIT);
779 :
780 : #ifdef ENABLE_PLUGIN
781 : /* Traverse and initialize each plugin specified in the command-line. */
782 253 : htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
783 : #endif
784 :
785 253 : timevar_pop (TV_PLUGIN_INIT);
786 : }
787 :
788 : /* Release memory used by one plugin. */
789 :
790 : static int
791 241 : finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
792 : {
793 241 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
794 241 : XDELETE (plugin);
795 241 : return 1;
796 : }
797 :
798 : /* Free memory allocated by the plugin system. */
799 :
800 : void
801 283661 : finalize_plugins (void)
802 : {
803 283661 : if (!plugin_name_args_tab)
804 : return;
805 :
806 : /* We can now delete the plugin_name_args object as it will no longer
807 : be used. Note that base_name and argv fields (both of which were also
808 : dynamically allocated) are not freed as they could still be used by
809 : the plugin code. */
810 :
811 241 : htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
812 :
813 : /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
814 241 : htab_delete (plugin_name_args_tab);
815 241 : plugin_name_args_tab = NULL;
816 : }
817 :
818 : /* Implementation detail of for_each_plugin. */
819 :
820 : struct for_each_plugin_closure
821 : {
822 : void (*cb) (const plugin_name_args *,
823 : void *user_data);
824 : void *user_data;
825 : };
826 :
827 : /* Implementation detail of for_each_plugin: callback for htab_traverse_noresize
828 : that calls the user-provided callback. */
829 :
830 : static int
831 11 : for_each_plugin_cb (void **slot, void *info)
832 : {
833 11 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
834 11 : for_each_plugin_closure *c = (for_each_plugin_closure *)info;
835 11 : c->cb (plugin, c->user_data);
836 11 : return 1;
837 : }
838 :
839 : /* Call CB with USER_DATA on each plugin. */
840 :
841 : void
842 114 : for_each_plugin (void (*cb) (const plugin_name_args *,
843 : void *user_data),
844 : void *user_data)
845 : {
846 114 : if (!plugin_name_args_tab)
847 103 : return;
848 :
849 11 : for_each_plugin_closure c;
850 11 : c.cb = cb;
851 11 : c.user_data = user_data;
852 :
853 11 : htab_traverse_noresize (plugin_name_args_tab, for_each_plugin_cb, &c);
854 : }
855 :
856 : /* Used to pass options to htab_traverse callbacks. */
857 :
858 : struct print_options
859 : {
860 : FILE *file;
861 : const char *indent;
862 : };
863 :
864 : /* Print the version of one plugin. */
865 :
866 : static int
867 0 : print_version_one_plugin (void **slot, void *data)
868 : {
869 0 : struct print_options *opt = (struct print_options *) data;
870 0 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
871 0 : const char *version = plugin->version ? plugin->version : "Unknown version.";
872 :
873 0 : fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
874 0 : return 1;
875 : }
876 :
877 : /* Print the version of each plugin. */
878 :
879 : void
880 124 : print_plugins_versions (FILE *file, const char *indent)
881 : {
882 124 : struct print_options opt;
883 124 : opt.file = file;
884 124 : opt.indent = indent;
885 124 : if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
886 124 : return;
887 :
888 0 : fprintf (file, "%sVersions of loaded plugins:\n", indent);
889 0 : htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
890 : }
891 :
892 : /* Print help for one plugin. SLOT is the hash table slot. DATA is the
893 : argument to htab_traverse_noresize. */
894 :
895 : static int
896 0 : print_help_one_plugin (void **slot, void *data)
897 : {
898 0 : struct print_options *opt = (struct print_options *) data;
899 0 : struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
900 0 : const char *help = plugin->help ? plugin->help : "No help available .";
901 :
902 0 : char *dup = xstrdup (help);
903 0 : char *p, *nl;
904 0 : fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
905 :
906 0 : for (p = nl = dup; nl; p = nl)
907 : {
908 0 : nl = strchr (nl, '\n');
909 0 : if (nl)
910 : {
911 0 : *nl = '\0';
912 0 : nl++;
913 : }
914 0 : fprintf (opt->file, " %s %s\n", opt->indent, p);
915 : }
916 :
917 0 : free (dup);
918 0 : return 1;
919 : }
920 :
921 : /* Print help for each plugin. The output goes to FILE and every line starts
922 : with INDENT. */
923 :
924 : void
925 3 : print_plugins_help (FILE *file, const char *indent)
926 : {
927 3 : struct print_options opt;
928 3 : opt.file = file;
929 3 : opt.indent = indent;
930 3 : if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
931 3 : return;
932 :
933 0 : fprintf (file, "%sHelp for the loaded plugins:\n", indent);
934 0 : htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
935 : }
936 :
937 :
938 : /* Return true if plugins have been loaded. */
939 :
940 : bool
941 22 : plugins_active_p (void)
942 : {
943 22 : int event;
944 :
945 550 : for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
946 528 : if (plugin_callbacks[event])
947 : return true;
948 :
949 : return false;
950 : }
951 :
952 :
953 : /* Dump to FILE the names and associated events for all the active
954 : plugins. */
955 :
956 : DEBUG_FUNCTION void
957 0 : dump_active_plugins (FILE *file)
958 : {
959 0 : int event;
960 :
961 0 : if (!plugins_active_p ())
962 : return;
963 :
964 0 : fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
965 0 : for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
966 0 : if (plugin_callbacks[event])
967 : {
968 0 : struct callback_info *ci;
969 :
970 0 : fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]);
971 :
972 0 : for (ci = plugin_callbacks[event]; ci; ci = ci->next)
973 0 : fprintf (file, " %s", ci->plugin_name);
974 :
975 0 : putc ('\n', file);
976 : }
977 : }
978 :
979 :
980 : /* Dump active plugins to stderr. */
981 :
982 : DEBUG_FUNCTION void
983 0 : debug_active_plugins (void)
984 : {
985 0 : dump_active_plugins (stderr);
986 0 : }
987 :
988 : /* Give a warning if plugins are present, before an ICE message asking
989 : to submit a bug report. */
990 :
991 : void
992 22 : warn_if_plugins (void)
993 : {
994 22 : if (plugins_active_p ())
995 : {
996 0 : fnotice (stderr, "*** WARNING *** there are active plugins, do not report"
997 : " this as a bug unless you can reproduce it without enabling"
998 : " any plugins.\n");
999 0 : dump_active_plugins (stderr);
1000 : }
1001 :
1002 22 : }
1003 :
1004 : /* The default version check. Compares every field in VERSION. */
1005 :
1006 : bool
1007 188 : plugin_default_version_check (struct plugin_gcc_version *gcc_version,
1008 : struct plugin_gcc_version *plugin_version)
1009 : {
1010 188 : if (!gcc_version || !plugin_version)
1011 : return false;
1012 :
1013 188 : if (strcmp (gcc_version->basever, plugin_version->basever))
1014 : return false;
1015 188 : if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
1016 : return false;
1017 188 : if (strcmp (gcc_version->devphase, plugin_version->devphase))
1018 : return false;
1019 188 : if (strcmp (gcc_version->revision, plugin_version->revision))
1020 : return false;
1021 188 : if (strcmp (gcc_version->configuration_arguments,
1022 : plugin_version->configuration_arguments))
1023 0 : return false;
1024 : return true;
1025 : }
1026 :
1027 :
1028 : /* Return the current value of event_last, so that plugins which provide
1029 : additional functionality for events for the benefit of high-level plugins
1030 : know how many valid entries plugin_event_name holds. */
1031 :
1032 : int
1033 0 : get_event_last (void)
1034 : {
1035 0 : return event_last;
1036 : }
1037 :
1038 :
1039 : /* Retrieve the default plugin directory. The gcc driver should have passed
1040 : it as -iplugindir <dir> to the cc1 program, and it is queriable through the
1041 : -print-file-name=plugin option to gcc. */
1042 : const char*
1043 111 : default_plugin_dir_name (void)
1044 : {
1045 111 : if (!plugindir_string)
1046 0 : fatal_error (input_location,
1047 : "%<-iplugindir%> option not passed from the gcc driver");
1048 111 : return plugindir_string;
1049 : }
|