LCOV - code coverage report
Current view: top level - gcc - plugin.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 63.9 % 371 237
Test Date: 2026-02-28 14:20:25 Functions: 67.9 % 28 19
Legend: Lines:     hit not hit

            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              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.